alsa-lib/src/pcm/pcm.c
Jaroslav Kysela c39882f602 Configuration:
- changed snd_config_get_id function to follow semantic of other get functions
  - added snd_config_test_id
  - added runtime pointer type (not persistent)
    - added snd_config_make_pointer, snd_config_set_pointer, snd_config_get_pointer
  - added type/contents checking for callback functions
    - changed 'void *private_data' to 'snd_config_t *private_data'
  - renamed card_strtype functions to card_driver
Control:
  - fixed passing parameters to snd_ctl_async
Async handlers:
  - added public snd_async_handler_get_signo function
Documentation:
  - moved all documentation to source files
2001-11-19 08:14:21 +00:00

5204 lines
161 KiB
C

/**
* \file pcm/pcm.c
* \ingroup PCM
* \brief PCM Interface
* \author Jaroslav Kysela <perex@suse.cz>
* \author Abramo Bagnara <abramo@alsa-project.org>
* \date 2000-2001
*
* PCM Interface is designed to write or read digital audio frames. A
* frame is the data unit converted into/from sound in one time unit
* (1/rate seconds), by example if you set your playback PCM rate to
* 44100 you'll hear 44100 frames per second. The size in bytes of a
* frame may be obtained from bits needed to store a sample and
* channels count.
*
* See the \ref pcm page for more details.
*/
/*
* PCM Interface - main file
* Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz>
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*! \page pcm PCM (digital audio) interface
<P>Although abbreviation PCM stands for Pulse Code Modulation, we are
understanding it as general digital audio processing with volume samples
generated in continuous time periods.</P>
<P>Digital audio is the most commonly used method of representing
sound inside a computer. In this method sound is stored as a sequence of
samples taken from the audio signal using constant time intervals.
A sample represents volume of the signal at the moment when it
was measured. In uncompressed digital audio each sample require one
or more bytes of storage. The number of bytes required depends on number
of channels (mono, stereo) and sample format (8 or 16 bits, mu-Law, etc.).
The length of this interval determines the sampling rate. Commonly used
sampling rates are between 8kHz (telephone quality) and
48kHz (DAT tapes).</P>
<P>The physical devices used in digital audio are called the
ADC (Analog to Digital Converter) and DAC (Digital to Analog Converter).
A device containing both ADC and DAC is commonly known as a codec.
The codec device used in a Sound Blaster cards is called a DSP which
is somewhat misleading since DSP also stands for Digital Signal Processor
(the SB DSP chip is very limited when compared to "true" DSP chips).</P>
<P>Sampling parameters affect the quality of sound which can be
reproduced from the recorded signal. The most fundamental parameter
is sampling rate which limits the highest frequency that can be stored.
It is well known (Nyquist's Sampling Theorem) that the highest frequency
that can be stored in a sampled signal is at most 1/2 of the sampling
frequency. For example, an 8 kHz sampling rate permits the recording of
a signal in which the highest frequency is less than 4 kHz. Higher frequency
signals must be filtered out before feeding them to ADC.</P>
<P>Sample encoding limits the dynamic range of a recorded signal
(difference between the faintest and the loudest signal that can be
recorded). In theory the maximum dynamic range of signal is number_of_bits *
6dB. This means that 8 bits sampling resolution gives dynamic range of
48dB and 16 bit resolution gives 96dB.</P>
<P>Quality has price. The number of bytes required to store an audio
sequence depends on sampling rate, number of channels and sampling
resolution. For example just 8000 bytes of memory is required to store
one second of sound using 8kHz/8 bits/mono but 48kHz/16bit/stereo takes
192 kilobytes. A 64 kbps ISDN channel is required to transfer a
8kHz/8bit/mono audio stream in real time, and about 1.5Mbps is required
for DAT quality (48kHz/16bit/stereo). On the other hand it is possible
to store just 5.46 seconds of sound in a megabyte of memory when using
48kHz/16bit/stereo sampling. With 8kHz/8bits/mono it is possible to store
131 seconds of sound using the same amount of memory. It is possible
to reduce memory and communication costs by compressing the recorded
signal but this is beyond the scope of this document. </P>
\section pcm_general_overview General overview
ALSA uses the ring buffer to store outgoing (playback) and incoming (capture,
record) samples. There are two pointers being mantained to allow
a precise communication between application and device pointing to current
processed sample by hardware and last processed sample by application.
The modern audio chips allow to program the transfer time periods.
It means that the stream of samples is divided to small chunks. Device
acknowledges to application when the transfer of a chunk is complete.
\section pcm_transfer Transfer methods in unix environments
In the unix environment, data chunk acknowledges are received via standard I/O
calls or event waiting routines (poll or select function). To accomplish
this list, the asynchronous notification of acknowledges should be listed
here. The ALSA implementation for these methods is described in
the \ref alsa_transfers section.
\subsection pcm_transfer_io Standard I/O transfers
The standard I/O transfers are using the read (see 'man 2 read') and write
(see 'man 2 write') C functions. There are two basic behaviours of these
functions - blocked and non-blocked (see the O_NONBLOCK flag for the
standard C open function - see 'man 2 open'). In non-blocked behaviour,
these I/O functions never stops, they return -EAGAIN error code, when no
data can be transferred (the ring buffer is full in our case). In blocked
behaviour, these I/O functions stop and wait until there is a room in the
ring buffer (playback) or until there are a new samples (capture). The ALSA
implementation can be found in the \ref alsa_pcm_rw section.
\subsection pcm_transfer_event Event waiting routines
The poll or select functions (see 'man 2 poll' or 'man 2 select' for further
details) allows to receive requests/events from the device while
an application is waiting on events from other sources (like keyboard, screen,
network etc.), too. The select function is old and deprecated in modern
applications, so the ALSA library does not support it. The implemented
transfer routines can be found in the \ref alsa_transfers section.
\subsection pcm_transfer_async Asynchronous notification
ALSA driver and library knows to handle the asynchronous notifications over
the SIGIO signal. This signal allows to interrupt application and transfer
data in the signal handler. For further details see the sigaction function
('man 2 sigaction'). The section \ref pcm_async describes the ALSA API for
this extension. The implemented transfer routines can be found in the
\ref alsa_transfers section.
\section pcm_open_behaviour Blocked and non-blocked open
The ALSA PCM API uses a different behaviour when the device is opened
with blocked or non-blocked mode. The mode can be specified with
\a mode argument in \link ::snd_pcm_open() \endlink function.
The blocked mode is the default (without \link ::SND_PCM_NONBLOCK \endlink mode).
In this mode, the behaviour is that if the resources have already used
with another application, then it blocks the caller, until resources are
free. The non-blocked behaviour (with \link ::SND_PCM_NONBLOCK \endlink)
doesn't block the caller in any way and returns -EBUSY error when the
resources are not available. Note that the mode also determines the
behaviour of standard I/O calls, returning -EAGAIN when non-blocked mode is
used and the ring buffer is full (playback) or empty (capture).
The operation mode for I/O calls can be changed later with
the \link snd_pcm_nonblock() \endlink function.
\section pcm_async Asynchronous mode
There is also possibility to receive asynchronous notification after
specified time periods. You may see the \link ::SND_PCM_ASYNC \endlink
mode for \link ::snd_pcm_open() \endlink function and
\link ::snd_async_add_pcm_handler() \endlink function for further details.
\section pcm_handshake Handshake between application and library
The ALSA PCM API design uses the states to determine the communication
phase between application and library. The actual state can be determined
using \link ::snd_pcm_state() \endlink call. There are these states:
\par SND_PCM_STATE_OPEN
The PCM device is in the open state. After the \link ::snd_pcm_open() \endlink open call,
the device is in this state. Also, when \link ::snd_pcm_hw_params() \endlink call fails,
then this state is entered to force application calling
\link ::snd_pcm_hw_params() \endlink function to set right communication
parameters.
\par SND_PCM_STATE_SETUP
The PCM device has accepted communication parameters and it is waiting
for \link ::snd_pcm_prepare() \endlink call to prepare the hardware for
selected operation (playback or capture).
\par SND_PCM_STATE_PREPARE
The PCM device is prepared for operation. Application can use
\link ::snd_pcm_start() \endlink call, write or read data to start
the operation.
\par SND_PCM_STATE_RUNNING
The PCM device is running. It processes the samples. The stream can
be stopped using the \link ::snd_pcm_drop() \endlink or
\link ::snd_pcm_drain \endlink calls.
\par SND_PCM_STATE_XRUN
The PCM device reached overrun (capture) or underrun (playback).
You can use the -EPIPE return code from I/O functions
(\link ::snd_pcm_writei() \endlink, \link ::snd_pcm_writen() \endlink,
\link ::snd_pcm_readi() \endlink, \link ::snd_pcm_readi() \endlink)
to determine this state without checking
the actual state via \link ::snd_pcm_state() \endlink call. You can recover from
this state with \link ::snd_pcm_prepare() \endlink,
\link ::snd_pcm_drop() \endlink or \link ::snd_pcm_drain() \endlink calls.
\par SND_PCM_STATE_DRAINING
The device is in this state when application using the capture mode
called \link ::snd_pcm_drain() \endlink function. Until all data are
read from the internal ring buffer using I/O routines
(\link ::snd_pcm_readi() \endlink, \link ::snd_pcm_readn() \endlink),
then the device stays in this state.
\par SND_PCM_STATE_PAUSED
The device is in this state when application called
the \link ::snd_pcm_pause() \endlink function until the pause is released.
Not all hardware supports this feature. Application should check the
capability with the \link ::snd_pcm_hw_params_can_pause() \endlink.
\par SND_PCM_STATE_SUSPENDED
The device is in the suspend state provoked with the power management
system. The stream can be resumed using \link ::snd_pcm_resume() \endlink
call, but not all hardware supports this feature. Application should check
the capability with the \link ::snd_pcm_hw_params_can_resume() \endlink.
In other case, the calls \link ::snd_pcm_prepare() \endlink,
\link ::snd_pcm_drop() \endlink, \link ::snd_pcm_drain() \endlink can be used
to leave this state.
\section pcm_formats PCM formats
The full list of formats present the \link ::snd_pcm_format_t \endlink type.
The 24-bit linear samples uses 32-bit physical space, but the sample is
stored in low three bits. Some hardware does not support processing of full
range, thus you may get the significative bits for linear samples via
\link ::snd_pcm_hw_params_get_sbits \endlink function. The example: ICE1712
chips support 32-bit sample processing, but low byte is ignored (playback)
or zero (capture). The function \link ::snd_pcm_hw_params_get_sbits() \endlink
returns 24 in the case.
\section alsa_transfers ALSA transfers
There are two methods to transfer samples in application. The first method
is the standard read / write one. The second method, uses the direct audio
buffer to communicate with the device while ALSA library manages this space
itself. You can find examples of all communication schemes for playback
in \ref example_test_pcm "Sine-wave generator example". To complete the
list, we should note that \link ::snd_pcm_wait \endlink function contains
embedded poll waiting implementation.
\subsection alsa_pcm_rw Read / Write transfer
There are two versions of read / write routines. The first expects the
interleaved samples at input, and the second one expects non-interleaved
(samples in separated buffers) at input. There are these functions for
interleaved transfers: \link ::snd_pcm_writei \endlink,
\link ::snd_pcm_readi \endlink. For non-interleaved transfers, there are
these functions: \link ::snd_pcm_writen \endlink and \link ::snd_pcm_readn
\endlink.
\subsection alsa_mmap_rw Direct Read / Write transfer (via mmaped areas)
There are two functions for this kind of transfer. Application can get an
access to memory areas via \link ::snd_pcm_mmap_begin \endlink function.
This functions returns the areas (single area is equal to a channel)
containing the direct pointers to memory and sample position description
in \link ::snd_pcm_channel_area_t \endlink structure. After application
transfers the data in the memory areas, then it must be acknowledged
the end of transfer via \link ::snd_pcm_mmap_commit() \endlink function
to allow the ALSA library update the pointers to ring buffer. This sort of
communication is also called "zero-copy", because the device does not require
to copy the samples from application to another place in system memory.
\par
If you like to use the compatibility functions in mmap mode, there are
read / write routines equaling to standard read / write transfers. Using
these functions discards the benefits of direct access to memory region.
See the \link ::snd_pcm_mmap_readi() \endlink,
\link ::snd_pcm_writei() \endlink, \link ::snd_pcm_readn() \endlink
and \link ::snd_pcm_writen() \endlink functions.
\section pcm_params Managing parameters
The ALSA PCM device uses two groups of PCM related parameters. The hardware
parameters contains the stream description like format, rate, count of
channels, ring buffer size etc. The software parameters contains the
software (driver) related parameters. The communicatino behaviour can be
controlled via these parameters, like automatic start, automatic stop,
interrupting (chunk acknowledge) etc. The software parameters can be
modified at any time (when valid hardware parameters are set). It includes
the running state as well.
\subsection pcm_hw_params Hardware related parameters
The ALSA PCM devices use the parameter refining system for hardware
parameters - \link ::snd_pcm_hw_params_t \endlink. It means, that
application choose the full-range of configurations at first and then
application sets single parameters until all parameters are elementary
(definite).
\par Access modes
ALSA knows about five access modes. The first three can be used for direct
communication. The access mode \link ::SND_PCM_ACCESS_MMAP_INTERLEAVED \endlink
determines the direct memory area and interleaved sample organization.
Interleaved organization means, that samples from channels are mixed together.
The access mode \link ::SND_PCM_ACCESS_MMAP_NONINTERLEAVED \endlink
determines the direct memory area and non-interleaved sample organization.
Each channel has a separate buffer in the case. The complex direct memory
organization represents the \link ::SND_PCM_ACCESS_MMAP_COMPLEX \endlink
access mode. The sample organization does not fit the interleaved or
non-interleaved access modes in the case. The last two access modes
describes the read / write access methods.
The \link ::SND_PCM_ACCESS_RW_INTERLEAVED \endlink access represents the read /
write interleaved access and the \link ::SND_PCM_ACCESS_RW_NONINTERLEAVED \endlink
represents the non-interleaved access.
\par Formats
The full list of formats is available in \link ::snd_pcm_format_t \endlink
enumeration.
\subsection pcm_sw_params Software related parameters
These parameters - \link ::snd_pcm_sw_params_t \endlink can be modified at
any time including the running state.
\par Minimum available count of samples
This parameter controls the wakeup point. If the count of available samples
is equal or greater than this value, then application will be activated.
\par Timestamp mode
The timestamp mode specifies, if timestamps are activated. Currently, only
\link ::SND_PCM_TSTAMP_NONE \endlink and \link ::SND_PCM_TSTAMP_MMAP
\endlink modes are known. The mmap mode means that timestamp is taken
on every period time boundary.
\par Minimal sleep
This parameters means the minimum of ticks to sleep using a standalone
timer (usually the system timer). The tick resolution can be obtained
via the function \link ::snd_pcm_hw_params_get_tick_time \endlink. This
function can be used to fine-tune the transfer acknowledge process. It could
be useful especially when some hardware does not support small transfer
periods.
\par Transfer align
The read / write transfers can be aligned to this sample count. The modulo
is ignored by device. Usually, this value is set to one (no align).
\par Start threshold
The start threshold parameter is used to determine the start point in
stream. For playback, if samples in ring buffer is equal or greater than
the start threshold parameters and the stream is not running, the stream will
be started automatically from the device. For capture, if the application wants
to read count of samples equal or greater then the stream will be started.
If you want to use explicit start (\link ::snd_pcm_start \endlink), you can
set this value greater than ring buffer size (in samples), but use the
constant MAXINT is not a bad idea.
\par Stop threshold
Similarly, the stop threshold parameter is used to automatically stop
the running stream, when the available samples crosses this boundary.
It means, for playback, the empty samples in ring buffer and for capture,
the filled (used) samples in ring buffer.
\par Silence threshold
The silence threshold specifies count of samples filled with silence
ahead of the current application pointer for playback. It is useable
for applications when an overrun is possible (like tasks depending on
network I/O etc.). If application wants to manage the ahead samples itself,
the \link ::snd_pcm_rewind() \endlink function allows to forget the last
samples in the stream.
\section pcm_status Obtaining device status
The device status is stored in \link ::snd_pcm_status_t \endlink structure.
These parameters can be obtained: the current stream state -
\link ::snd_pcm_status_get_state \endlink, timestamp of trigger -
\link ::snd_pcm_status_get_trigger_tstamp \endlink, timestamp of last
update \link ::snd_pcm_status_get_tstamp \endlink, delay in samples -
\link ::snd_pcm_status_get_delay \endlink, available count in samples -
\link ::snd_pcm_status_get_avail \endlink, maximum available samples -
\link ::snd_pcm_status_get_avail_max \endlink, ADC overrange count in
samples - \link ::snd_pcm_status_get_overrange \endlink. The last two
parameters - avail_max and overrange are reset to zero after the status
call.
\subsection pcm_status_fast Obtaining fast device status
The function \link ::snd_pcm_avail_update \endlink updates the current
available count of samples for writting (playback) or filled samples for
reading (capture).
<p>
The function \link ::snd_pcm_delay \endlink returns the delay in samples.
For playback, it means count of samples in the ring buffer before
the next sample will be sent to DAC. For capture, it means count of samples
in the ring buffer before the next sample will be captured from ADC.
\section pcm_action Managing the stream state
These functions directly and indirectly affecting the stream state:
\par snd_pcm_hw_params
The \link ::snd_pcm_hw_params \endlink function brings the stream state
to \link ::SND_PCM_STATE_SETUP \endlink
if successfully finishes, otherwise the state \link ::SND_PCM_STATE_OPEN
\endlink is entered.
\par snd_pcm_prepare
The \link ::snd_pcm_prepare \endlink function enters the
\link ::SND_PCM_STATE_PREPARED \endlink after a successfull finish.
\par snd_pcm_start
The \link ::snd_pcm_start \endlink function enters
the \link ::SND_PCM_STATE_RUNNING \endlink after a successfull finish.
\par snd_pcm_drop
The \link ::snd_pcm_drop \endlink function enters the
\link ::SND_PCM_STATE_SETUP \endlink state.
\par snd_pcm_drain
The \link ::snd_pcm_drain \endlink function enters the
\link ::SND_PCM_STATE_DRAINING \endlink, if
the capture device has some samples in the ring buffer otherwise
\link ::SND_PCM_STATE_SETUP \endlink state is entered.
\par snd_pcm_pause
The \link ::snd_pcm_pause \endlink function enters the
\link ::SND_PCM_STATE_PAUSED \endlink or
\link ::SND_PCM_STATE_RUNNING \endlink.
\par snd_pcm_writei, snd_pcm_writen
The \link ::snd_pcm_writei \endlink and \link ::snd_pcm_writen \endlink
functions can conditionally start the stream -
\link ::SND_PCM_STATE_RUNNING \endlink. They depend on the start threshold
software parameter.
\par snd_pcm_readi, snd_pcm_readn
The \link ::snd_pcm_readi \endlink and \link ::snd_pcm_readn \endlink
functions can conditionally start the stream -
\link ::SND_PCM_STATE_RUNNING \endlink. They depend on the start threshold
software parameter.
\section pcm_sync Streams synchronization
There are two functions allowing link multiple streams together. In the
case, the linking means that all operations are synchronized. Because the
drivers cannot guarantee the synchronization (sample resolution) on hardware
lacking this feature, the \link ::snd_pcm_info_get_sync \endlink function
returns synchronization ID - \link ::snd_pcm_sync_id_t \endlink, which is equal
for hardware synchronizated streams. When the \link ::snd_pcm_link \endlink
function is called, all operations managing the stream state for these two
streams are joined. The oposite function is \link ::snd_pcm_unlink \endlink.
\section pcm_examples Examples
The full featured examples with cross-links:
\par Sine-wave generator
\ref example_test_pcm "example code"
\par
This example shows various transfer methods for the playback direction.
\par Latency measuring tool
\ref example_test_latency "example code"
\par
This example shows the measuring of minimal latency between capture and
playback devices.
*/
/**
* \example ../test/pcm.c
* \anchor example_test_pcm
*/
/**
* \example ../test/latency.c
* \anchor example_test_latency
*/
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdarg.h>
#include <signal.h>
#include <dlfcn.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <limits.h>
#include "pcm_local.h"
/**
* \brief get identifier of PCM handle
* \param pcm PCM handle
* \return ascii identifier of PCM handle
*
* Returns the ASCII identifier of given PCM handle. It's the same
* identifier specified in snd_pcm_open().
*/
const char *snd_pcm_name(snd_pcm_t *pcm)
{
assert(pcm);
return pcm->name;
}
/**
* \brief get type of PCM handle
* \param pcm PCM handle
* \return type of PCM handle
*
* Returns the type #snd_pcm_type_t of given PCM handle.
*/
snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm)
{
assert(pcm);
return pcm->type;
}
/**
* \brief get stream for a PCM handle
* \param pcm PCM handle
* \return stream of PCM handle
*
* Returns the type #snd_pcm_stream_t of given PCM handle.
*/
snd_pcm_stream_t snd_pcm_stream(snd_pcm_t *pcm)
{
assert(pcm);
return pcm->stream;
}
/**
* \brief close PCM handle
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
*
* Closes the specified PCM handle and frees all associated
* resources.
*/
int snd_pcm_close(snd_pcm_t *pcm)
{
int err;
assert(pcm);
if (pcm->setup) {
if ((pcm->mode & SND_PCM_NONBLOCK) ||
pcm->stream == SND_PCM_STREAM_CAPTURE)
snd_pcm_drop(pcm);
else
snd_pcm_drain(pcm);
err = snd_pcm_hw_free(pcm);
if (err < 0)
return err;
}
while (!list_empty(&pcm->async_handlers)) {
snd_async_handler_t *h = list_entry(&pcm->async_handlers.next, snd_async_handler_t, hlist);
snd_async_del_handler(h);
}
err = pcm->ops->close(pcm->op_arg);
if (err < 0)
return err;
if (pcm->name)
free(pcm->name);
free(pcm);
return 0;
}
/**
* \brief set nonblock mode
* \param pcm PCM handle
* \param nonblock 0 = block, 1 = nonblock mode
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock)
{
int err;
assert(pcm);
if ((err = pcm->ops->nonblock(pcm->op_arg, nonblock)) < 0)
return err;
if (nonblock)
pcm->mode |= SND_PCM_NONBLOCK;
else
pcm->mode &= ~SND_PCM_NONBLOCK;
return 0;
}
#ifndef DOC_HIDDEN
/**
* \brief set async mode
* \param pcm PCM handle
* \param sig Signal to raise: < 0 disable, 0 default (SIGIO)
* \param pid Process ID to signal: 0 current
* \return 0 on success otherwise a negative error code
*
* A signal is raised every period.
*/
int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid)
{
assert(pcm);
if (sig == 0)
sig = SIGIO;
if (pid == 0)
pid = getpid();
return pcm->ops->async(pcm->op_arg, sig, pid);
}
#endif
/**
* \brief Obtain general (static) information for PCM handle
* \param pcm PCM handle
* \param info Information container
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
{
assert(pcm && info);
return pcm->ops->info(pcm->op_arg, info);
}
/** \brief Install one PCM hardware configuration choosen from a configuration space and #snd_pcm_prepare it
* \param pcm PCM handle
* \param params Configuration space definition container
* \return 0 on success otherwise a negative error code
*
* The configuration is choosen fixing single parameters in this order:
* first access, first format, first subformat, min channels, min rate,
* min period time, max buffer size, min tick time
*/
int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
int err;
assert(pcm && params);
err = _snd_pcm_hw_params(pcm, params);
if (err < 0)
return err;
err = snd_pcm_prepare(pcm);
return err;
}
/** \brief Remove PCM hardware configuration and free associated resources
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_hw_free(snd_pcm_t *pcm)
{
int err;
assert(pcm->setup);
if (pcm->mmap_channels) {
err = snd_pcm_munmap(pcm);
if (err < 0)
return err;
}
assert(snd_pcm_state(pcm) == SND_PCM_STATE_SETUP ||
snd_pcm_state(pcm) == SND_PCM_STATE_PREPARED);
err = pcm->ops->hw_free(pcm->op_arg);
pcm->setup = 0;
if (err < 0)
return err;
return 0;
}
/** \brief Install PCM software configuration defined by params
* \param pcm PCM handle
* \param params Configuration container
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
{
int err;
err = pcm->ops->sw_params(pcm->op_arg, params);
if (err < 0)
return err;
pcm->tstamp_mode = snd_pcm_sw_params_get_tstamp_mode(params);
pcm->period_step = params->period_step;
pcm->sleep_min = params->sleep_min;
pcm->avail_min = params->avail_min;
pcm->xfer_align = params->xfer_align;
pcm->start_threshold = params->start_threshold;
pcm->stop_threshold = params->stop_threshold;
pcm->silence_threshold = params->silence_threshold;
pcm->silence_size = params->silence_size;
pcm->boundary = params->boundary;
return 0;
}
/**
* \brief Obtain status (runtime) information for PCM handle
* \param pcm PCM handle
* \param status Status container
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
{
assert(pcm && status);
return pcm->fast_ops->status(pcm->fast_op_arg, status);
}
/**
* \brief Return PCM state
* \param pcm PCM handle
* \return PCM state #snd_pcm_state_t of given PCM handle
*/
snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm)
{
assert(pcm);
return pcm->fast_ops->state(pcm->fast_op_arg);
}
/**
* \brief Obtain delay for a running PCM handle
* \param pcm PCM handle
* \param delayp Returned delay in frames
* \return 0 on success otherwise a negative error code
*
* Delay is distance between current application frame position and
* sound frame position.
* It's positive and less than buffer size in normal situation,
* negative on playback underrun and greater than buffer size on
* capture overrun.
*/
int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{
assert(pcm);
assert(pcm->setup);
return pcm->fast_ops->delay(pcm->fast_op_arg, delayp);
}
/**
* \brief Resume from suspend, no samples are lost
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
* \retval -EAGAIN resume can't be proceed immediately (audio hardware is probably still suspended)
* \retval -ENOSYS hardware doesn't support this feature
*
* This function can be used when the stream is in the suspend state
* to do the fine resume from this state. Not all hardware supports
* this feature, when an -ENOSYS error is returned, use the snd_pcm_prepare
* function to recovery.
*/
int snd_pcm_resume(snd_pcm_t *pcm)
{
assert(pcm);
assert(pcm->setup);
return pcm->fast_ops->resume(pcm->fast_op_arg);
}
/**
* \brief Prepare PCM for use
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_prepare(snd_pcm_t *pcm)
{
assert(pcm);
assert(pcm->setup);
return pcm->fast_ops->prepare(pcm->fast_op_arg);
}
/**
* \brief Reset PCM position
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
*
* Reduce PCM delay to 0.
*/
int snd_pcm_reset(snd_pcm_t *pcm)
{
assert(pcm);
assert(pcm->setup);
return pcm->fast_ops->reset(pcm->fast_op_arg);
}
/**
* \brief Start a PCM
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_start(snd_pcm_t *pcm)
{
assert(pcm);
assert(pcm->setup);
return pcm->fast_ops->start(pcm->fast_op_arg);
}
/**
* \brief Stop a PCM dropping pending frames
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_drop(snd_pcm_t *pcm)
{
assert(pcm);
assert(pcm->setup);
return pcm->fast_ops->drop(pcm->fast_op_arg);
}
/**
* \brief Stop a PCM preserving pending frames
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
* \retval -ESTRPIPE a suspend event occured
*
* For playback wait for all pending frames to be played and then stop
* the PCM.
* For capture stop PCM permitting to retrieve residual frames.
*/
int snd_pcm_drain(snd_pcm_t *pcm)
{
assert(pcm);
assert(pcm->setup);
return pcm->fast_ops->drain(pcm->fast_op_arg);
}
/**
* \brief Pause/resume PCM
* \param pcm PCM handle
* \param pause 0 = resume, 1 = pause
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_pause(snd_pcm_t *pcm, int enable)
{
assert(pcm);
assert(pcm->setup);
return pcm->fast_ops->pause(pcm->fast_op_arg, enable);
}
/**
* \brief Move application frame position backward
* \param pcm PCM handle
* \param frames wanted displacement in frames
* \return a positive number for actual displacement otherwise a
* negative error code
*/
snd_pcm_sframes_t snd_pcm_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
assert(pcm);
assert(pcm->setup);
assert(frames > 0);
return pcm->fast_ops->rewind(pcm->fast_op_arg, frames);
}
/**
* \brief Write interleaved frames to a PCM
* \param pcm PCM handle
* \param buffer frames containing buffer
* \param size frames to be written
* \return a positive number of frames actually written otherwise a
* negative error code
* \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
* \retval -EPIPE an underrun occured
* \retval -ESTRPIPE a suspend event occured (stream is suspended and waiting for an application recovery)
*
* If the blocking behaviour is selected, then routine waits until
* all requested bytes are played or put to the playback ring buffer.
* The count of bytes can be less only if a signal or underrun occured.
*
* If the non-blocking behaviour is selected, then routine doesn't wait at all.
*/
snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
{
assert(pcm);
assert(size == 0 || buffer);
assert(pcm->setup);
assert(pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED);
return _snd_pcm_writei(pcm, buffer, size);
}
/**
* \brief Write non interleaved frames to a PCM
* \param pcm PCM handle
* \param bufs frames containing buffers (one for each channel)
* \param size frames to be written
* \return a positive number of frames actually written otherwise a
* negative error code
* \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
* \retval -EPIPE an underrun occured
* \retval -ESTRPIPE a suspend event occured (stream is suspended and waiting for an application recovery)
*
* If the blocking behaviour is selected, then routine waits until
* all requested bytes are played or put to the playback ring buffer.
* The count of bytes can be less only if a signal or underrun occured.
*
* If the non-blocking behaviour is selected, then routine doesn't wait at all.
*/
snd_pcm_sframes_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
{
assert(pcm);
assert(size == 0 || bufs);
assert(pcm->setup);
assert(pcm->access == SND_PCM_ACCESS_RW_NONINTERLEAVED);
return _snd_pcm_writen(pcm, bufs, size);
}
/**
* \brief Read interleaved frames from a PCM
* \param pcm PCM handle
* \param buffer frames containing buffer
* \param size frames to be written
* \return a positive number of frames actually read otherwise a
* negative error code
* \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
* \retval -EPIPE an overrun occured
* \retval -ESTRPIPE a suspend event occured (stream is suspended and waiting for an application recovery)
*
* If the blocking behaviour was selected, then routine waits until
* all requested bytes are filled. The count of bytes can be less only
* if a signal or underrun occured.
*
* If the non-blocking behaviour is selected, then routine doesn't wait at all.
*/
snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
{
assert(pcm);
assert(size == 0 || buffer);
assert(pcm->setup);
assert(pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED);
return _snd_pcm_readi(pcm, buffer, size);
}
/**
* \brief Read non interleaved frames to a PCM
* \param pcm PCM handle
* \param bufs frames containing buffers (one for each channel)
* \param size frames to be written
* \return a positive number of frames actually read otherwise a
* negative error code
* \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING)
* \retval -EPIPE an overrun occured
* \retval -ESTRPIPE a suspend event occured (stream is suspended and waiting for an application recovery)
*
* If the blocking behaviour was selected, then routine waits until
* all requested bytes are filled. The count of bytes can be less only
* if a signal or underrun occured.
*
* If the non-blocking behaviour is selected, then routine doesn't wait at all.
*/
snd_pcm_sframes_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
{
assert(pcm);
assert(size == 0 || bufs);
assert(pcm->setup);
assert(pcm->access == SND_PCM_ACCESS_RW_NONINTERLEAVED);
return _snd_pcm_readn(pcm, bufs, size);
}
/**
* \brief Link two PCMs
* \param pcm1 first PCM handle
* \param pcm2 first PCM handle
* \return 0 on success otherwise a negative error code
*
* The two PCMs will start/stop/prepare in sync.
*/
int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
{
int fd1 = _snd_pcm_link_descriptor(pcm1);
int fd2 = _snd_pcm_link_descriptor(pcm2);
if (fd1 < 0 || fd2 < 0)
return -ENOSYS;
if (ioctl(fd1, SNDRV_PCM_IOCTL_LINK, fd2) < 0) {
SYSERR("SNDRV_PCM_IOCTL_LINK failed");
return -errno;
}
return 0;
}
/**
* \brief Remove a PCM from a linked group
* \param pcm PCM handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_unlink(snd_pcm_t *pcm)
{
int fd;
fd = _snd_pcm_link_descriptor(pcm);
if (ioctl(fd, SNDRV_PCM_IOCTL_UNLINK) < 0) {
SYSERR("SNDRV_PCM_IOCTL_UNLINK failed");
return -errno;
}
return 0;
}
/**
* \brief get count of poll descriptors for PCM handle
* \param pcm PCM handle
* \return count of poll descriptors
*/
int snd_pcm_poll_descriptors_count(snd_pcm_t *pcm)
{
assert(pcm);
return 1;
}
/**
* \brief get poll descriptors
* \param pcm PCM handle
* \param pfds array of poll descriptors
* \param space space in the poll descriptor array
* \return count of filled descriptors
*/
int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
{
assert(pcm);
if (space >= 1) {
pfds->fd = pcm->poll_fd;
pfds->events = pcm->stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
}
return 1;
}
#ifndef DOC_HIDDEN
#define STATE(v) [SND_PCM_STATE_##v] = #v
#define STREAM(v) [SND_PCM_STREAM_##v] = #v
#define READY(v) [SND_PCM_READY_##v] = #v
#define XRUN(v) [SND_PCM_XRUN_##v] = #v
#define SILENCE(v) [SND_PCM_SILENCE_##v] = #v
#define TSTAMP(v) [SND_PCM_TSTAMP_##v] = #v
#define ACCESS(v) [SND_PCM_ACCESS_##v] = #v
#define START(v) [SND_PCM_START_##v] = #v
#define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v
#define SW_PARAM(v) [SND_PCM_SW_PARAM_##v] = #v
#define FORMAT(v) [SND_PCM_FORMAT_##v] = #v
#define SUBFORMAT(v) [SND_PCM_SUBFORMAT_##v] = #v
#define FORMATD(v, d) [SND_PCM_FORMAT_##v] = d
#define SUBFORMATD(v, d) [SND_PCM_SUBFORMAT_##v] = d
static const char *snd_pcm_stream_names[] = {
STREAM(PLAYBACK),
STREAM(CAPTURE),
};
static const char *snd_pcm_state_names[] = {
STATE(OPEN),
STATE(SETUP),
STATE(PREPARED),
STATE(RUNNING),
STATE(XRUN),
STATE(DRAINING),
STATE(PAUSED),
STATE(SUSPENDED),
};
static const char *snd_pcm_access_names[] = {
ACCESS(MMAP_INTERLEAVED),
ACCESS(MMAP_NONINTERLEAVED),
ACCESS(MMAP_COMPLEX),
ACCESS(RW_INTERLEAVED),
ACCESS(RW_NONINTERLEAVED),
};
static const char *snd_pcm_format_names[] = {
FORMAT(S8),
FORMAT(U8),
FORMAT(S16_LE),
FORMAT(S16_BE),
FORMAT(U16_LE),
FORMAT(U16_BE),
FORMAT(S24_LE),
FORMAT(S24_BE),
FORMAT(U24_LE),
FORMAT(U24_BE),
FORMAT(S32_LE),
FORMAT(S32_BE),
FORMAT(U32_LE),
FORMAT(U32_BE),
FORMAT(FLOAT_LE),
FORMAT(FLOAT_BE),
FORMAT(FLOAT64_LE),
FORMAT(FLOAT64_BE),
FORMAT(IEC958_SUBFRAME_LE),
FORMAT(IEC958_SUBFRAME_BE),
FORMAT(MU_LAW),
FORMAT(A_LAW),
FORMAT(IMA_ADPCM),
FORMAT(MPEG),
FORMAT(GSM),
FORMAT(SPECIAL),
};
static const char *snd_pcm_format_descriptions[] = {
FORMATD(S8, "Signed 8 bit"),
FORMATD(U8, "Unsigned 8 bit"),
FORMATD(S16_LE, "Signed 16 bit Little Endian"),
FORMATD(S16_BE, "Signed 16 bit Big Endian"),
FORMATD(U16_LE, "Unsigned 16 bit Little Endian"),
FORMATD(U16_BE, "Unsigned 16 bit Big Endian"),
FORMATD(S24_LE, "Signed 24 bit Little Endian"),
FORMATD(S24_BE, "Signed 24 bit Big Endian"),
FORMATD(U24_LE, "Unsigned 24 bit Little Endian"),
FORMATD(U24_BE, "Unsigned 24 bit Big Endian"),
FORMATD(S32_LE, "Signed 32 bit Little Endian"),
FORMATD(S32_BE, "Signed 32 bit Big Endian"),
FORMATD(U32_LE, "Unsigned 32 bit Little Endian"),
FORMATD(U32_BE, "Unsigned 32 bit Big Endian"),
FORMATD(FLOAT_LE, "Float 32 bit Little Endian"),
FORMATD(FLOAT_BE, "Float 32 bit Big Endian"),
FORMATD(FLOAT64_LE, "Float 64 bit Little Endian"),
FORMATD(FLOAT64_BE, "Float 64 bit Big Endian"),
FORMATD(IEC958_SUBFRAME_LE, "IEC-958 Little Endian"),
FORMATD(IEC958_SUBFRAME_BE, "IEC-958 Big Endian"),
FORMATD(MU_LAW, "Mu-Law"),
FORMATD(A_LAW, "A-Law"),
FORMATD(IMA_ADPCM, "Ima-ADPCM"),
FORMATD(MPEG, "MPEG"),
FORMATD(GSM, "GSM"),
FORMATD(SPECIAL, "Special"),
};
static const char *snd_pcm_subformat_names[] = {
SUBFORMAT(STD),
};
static const char *snd_pcm_subformat_descriptions[] = {
SUBFORMATD(STD, "Standard"),
};
static const char *snd_pcm_start_mode_names[] = {
START(EXPLICIT),
START(DATA),
};
static const char *snd_pcm_xrun_mode_names[] = {
XRUN(NONE),
XRUN(STOP),
};
static const char *snd_pcm_tstamp_mode_names[] = {
TSTAMP(NONE),
TSTAMP(MMAP),
};
#endif
/**
* \brief get name of PCM stream
* \param stream PCM stream
* \return ascii name of PCM stream
*/
const char *snd_pcm_stream_name(snd_pcm_stream_t stream)
{
assert(stream <= SND_PCM_STREAM_LAST);
return snd_pcm_stream_names[stream];
}
/**
* \brief get name of PCM access type
* \param access PCM access type
* \return ascii name of PCM access type
*/
const char *snd_pcm_access_name(snd_pcm_access_t acc)
{
assert(acc <= SND_PCM_ACCESS_LAST);
return snd_pcm_access_names[acc];
}
/**
* \brief get name of PCM sample format
* \param format PCM sample format
* \return ascii name of PCM sample format
*/
const char *snd_pcm_format_name(snd_pcm_format_t format)
{
assert(format <= SND_PCM_FORMAT_LAST);
return snd_pcm_format_names[format];
}
/**
* \brief get description of PCM sample format
* \param format PCM sample format
* \return ascii description of PCM sample format
*/
const char *snd_pcm_format_description(snd_pcm_format_t format)
{
assert(format <= SND_PCM_FORMAT_LAST);
return snd_pcm_format_descriptions[format];
}
/**
* \brief get PCM sample format from name
* \param name PCM sample format name (case insensitive)
* \return PCM sample format
*/
snd_pcm_format_t snd_pcm_format_value(const char* name)
{
snd_pcm_format_t format;
for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
if (snd_pcm_format_names[format] &&
strcasecmp(name, snd_pcm_format_names[format]) == 0) {
return format;
}
}
return SND_PCM_FORMAT_UNKNOWN;
}
/**
* \brief get name of PCM sample subformat
* \param format PCM sample subformat
* \return ascii name of PCM sample subformat
*/
const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat)
{
assert(subformat <= SND_PCM_SUBFORMAT_LAST);
return snd_pcm_subformat_names[subformat];
}
/**
* \brief get description of PCM sample subformat
* \param subformat PCM sample subformat
* \return ascii description of PCM sample subformat
*/
const char *snd_pcm_subformat_description(snd_pcm_subformat_t subformat)
{
assert(subformat <= SND_PCM_SUBFORMAT_LAST);
return snd_pcm_subformat_descriptions[subformat];
}
/**
* \brief (DEPRECATED) get name of PCM start mode setting
* \param mode PCM start mode
* \return ascii name of PCM start mode setting
*/
const char *snd_pcm_start_mode_name(snd_pcm_start_t mode)
{
assert(mode <= SND_PCM_START_LAST);
return snd_pcm_start_mode_names[mode];
}
#ifndef DOC_HIDDEN
link_warning(snd_pcm_start_mode_name, "Warning: start_mode is deprecated, consider to use start_threshold");
#endif
/**
* \brief (DEPRECATED) get name of PCM xrun mode setting
* \param mode PCM xrun mode
* \return ascii name of PCM xrun mode setting
*/
const char *snd_pcm_xrun_mode_name(snd_pcm_xrun_t mode)
{
assert(mode <= SND_PCM_XRUN_LAST);
return snd_pcm_xrun_mode_names[mode];
}
#ifndef DOC_HIDDEN
link_warning(snd_pcm_xrun_mode_name, "Warning: xrun_mode is deprecated, consider to use stop_threshold");
#endif
/**
* \brief get name of PCM tstamp mode setting
* \param mode PCM tstamp mode
* \return ascii name of PCM tstamp mode setting
*/
const char *snd_pcm_tstamp_mode_name(snd_pcm_tstamp_t mode)
{
assert(mode <= SND_PCM_TSTAMP_LAST);
return snd_pcm_tstamp_mode_names[mode];
}
/**
* \brief get name of PCM state
* \param state PCM state
* \return ascii name of PCM state
*/
const char *snd_pcm_state_name(snd_pcm_state_t state)
{
assert(state <= SND_PCM_STATE_LAST);
return snd_pcm_state_names[state];
}
/**
* \brief Dump current hardware setup for PCM
* \param pcm PCM handle
* \param out Output handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_dump_hw_setup(snd_pcm_t *pcm, snd_output_t *out)
{
assert(pcm);
assert(out);
assert(pcm->setup);
snd_output_printf(out, "stream : %s\n", snd_pcm_stream_name(pcm->stream));
snd_output_printf(out, "access : %s\n", snd_pcm_access_name(pcm->access));
snd_output_printf(out, "format : %s\n", snd_pcm_format_name(pcm->format));
snd_output_printf(out, "subformat : %s\n", snd_pcm_subformat_name(pcm->subformat));
snd_output_printf(out, "channels : %u\n", pcm->channels);
snd_output_printf(out, "rate : %u\n", pcm->rate);
snd_output_printf(out, "exact rate : %g (%u/%u)\n", (double) pcm->rate_num / pcm->rate_den, pcm->rate_num, pcm->rate_den);
snd_output_printf(out, "msbits : %u\n", pcm->msbits);
snd_output_printf(out, "buffer_size : %lu\n", pcm->buffer_size);
snd_output_printf(out, "period_size : %lu\n", pcm->period_size);
snd_output_printf(out, "period_time : %u\n", pcm->period_time);
snd_output_printf(out, "tick_time : %u\n", pcm->tick_time);
return 0;
}
/**
* \brief Dump current software setup for PCM
* \param pcm PCM handle
* \param out Output handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, snd_output_t *out)
{
assert(pcm);
assert(out);
assert(pcm->setup);
snd_output_printf(out, "tstamp_mode : %s\n", snd_pcm_tstamp_mode_name(pcm->tstamp_mode));
snd_output_printf(out, "period_step : %d\n", pcm->period_step);
snd_output_printf(out, "sleep_min : %d\n", pcm->sleep_min);
snd_output_printf(out, "avail_min : %ld\n", pcm->avail_min);
snd_output_printf(out, "xfer_align : %ld\n", pcm->xfer_align);
snd_output_printf(out, "start_threshold : %ld\n", pcm->start_threshold);
snd_output_printf(out, "stop_threshold : %ld\n", pcm->stop_threshold);
snd_output_printf(out, "silence_threshold: %ld\n", pcm->silence_threshold);
snd_output_printf(out, "silence_size : %ld\n", pcm->silence_size);
snd_output_printf(out, "boundary : %ld\n", pcm->boundary);
return 0;
}
/**
* \brief Dump current setup (hardware and software) for PCM
* \param pcm PCM handle
* \param out Output handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_dump_setup(snd_pcm_t *pcm, snd_output_t *out)
{
snd_pcm_dump_hw_setup(pcm, out);
snd_pcm_dump_sw_setup(pcm, out);
return 0;
}
/**
* \brief Dump status
* \param status Status container
* \param out Output handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_status_dump(snd_pcm_status_t *status, snd_output_t *out)
{
assert(status);
snd_output_printf(out, "state : %s\n", snd_pcm_state_name((snd_pcm_state_t) status->state));
snd_output_printf(out, "trigger_time: %ld.%06ld\n",
status->trigger_tstamp.tv_sec, status->trigger_tstamp.tv_usec);
snd_output_printf(out, "tstamp : %ld.%06ld\n",
status->tstamp.tv_sec, status->tstamp.tv_usec);
snd_output_printf(out, "delay : %ld\n", (long)status->delay);
snd_output_printf(out, "avail : %ld\n", (long)status->avail);
snd_output_printf(out, "avail_max : %ld\n", (long)status->avail_max);
return 0;
}
/**
* \brief Dump PCM info
* \param pcm PCM handle
* \param out Output handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_dump(snd_pcm_t *pcm, snd_output_t *out)
{
assert(pcm);
assert(out);
pcm->ops->dump(pcm->op_arg, out);
return 0;
}
/**
* \brief Convert bytes in frames for a PCM
* \param pcm PCM handle
* \param bytes quantity in bytes
* \return quantity expressed in frames
*/
snd_pcm_sframes_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes)
{
assert(pcm);
assert(pcm->setup);
return bytes * 8 / pcm->frame_bits;
}
/**
* \brief Convert frames in bytes for a PCM
* \param pcm PCM handle
* \param frames quantity in frames
* \return quantity expressed in bytes
*/
ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, snd_pcm_sframes_t frames)
{
assert(pcm);
assert(pcm->setup);
return frames * pcm->frame_bits / 8;
}
/**
* \brief Convert bytes in samples for a PCM
* \param pcm PCM handle
* \param bytes quantity in bytes
* \return quantity expressed in samples
*/
int snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes)
{
assert(pcm);
assert(pcm->setup);
return bytes * 8 / pcm->sample_bits;
}
/**
* \brief Convert samples in bytes for a PCM
* \param pcm PCM handle
* \param samples quantity in samples
* \return quantity expressed in bytes
*/
ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, int samples)
{
assert(pcm);
assert(pcm->setup);
return samples * pcm->sample_bits / 8;
}
/**
* \brief Add an async handler for a PCM
* \param handler Returned handler handle
* \param pcm PCM handle
* \param callback Callback function
* \param private_data Callback private data
* \return 0 otherwise a negative error code on failure
*/
int snd_async_add_pcm_handler(snd_async_handler_t **handler, snd_pcm_t *pcm,
snd_async_callback_t callback, void *private_data)
{
int err;
int was_empty;
snd_async_handler_t *h;
err = snd_async_add_handler(&h, _snd_pcm_async_descriptor(pcm),
callback, private_data);
if (err < 0)
return err;
h->type = SND_ASYNC_HANDLER_PCM;
h->u.pcm = pcm;
was_empty = list_empty(&pcm->async_handlers);
list_add_tail(&h->hlist, &pcm->async_handlers);
if (was_empty) {
err = snd_pcm_async(pcm, snd_async_signo(h), getpid());
if (err < 0) {
snd_async_del_handler(h);
return err;
}
}
*handler = h;
return 0;
}
/**
* \brief Return PCM handle related to an async handler
* \param handler Async handler handle
* \return PCM handle
*/
snd_pcm_t *snd_async_handler_get_pcm(snd_async_handler_t *handler)
{
assert(handler->type = SND_ASYNC_HANDLER_PCM);
return handler->u.pcm;
}
static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,
snd_config_t *pcm_root, snd_config_t *pcm_conf,
snd_pcm_stream_t stream, int mode)
{
const char *str;
char buf[256];
int err;
snd_config_t *conf, *type_conf = NULL;
snd_config_iterator_t i, next;
const char *id;
const char *lib = NULL, *open_name = NULL;
int (*open_func)(snd_pcm_t **, const char *,
snd_config_t *, snd_config_t *,
snd_pcm_stream_t, int) = NULL;
#ifndef PIC
extern void *snd_pcm_open_symbols(void);
#endif
void *h;
if (snd_config_get_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) {
if (name)
SNDERR("Invalid type for PCM %s definition", name);
else
SNDERR("Invalid type for PCM definition");
return -EINVAL;
}
err = snd_config_search(pcm_conf, "type", &conf);
if (err < 0) {
SNDERR("type is not defined");
return err;
}
err = snd_config_get_id(conf, &id);
if (err < 0) {
SNDERR("unable to get id");
return err;
}
err = snd_config_get_string(conf, &str);
if (err < 0) {
SNDERR("Invalid type for %s", id);
return err;
}
err = snd_config_search_definition(pcm_root, "pcm_type", str, &type_conf);
if (err >= 0) {
if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) {
SNDERR("Invalid type for PCM type %s definition", str);
goto _err;
}
snd_config_for_each(i, next, type_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
const char *id;
if (snd_config_get_id(n, &id) < 0)
continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
err = snd_config_get_string(n, &lib);
if (err < 0) {
SNDERR("Invalid type for %s", id);
goto _err;
}
continue;
}
if (strcmp(id, "open") == 0) {
err = snd_config_get_string(n, &open_name);
if (err < 0) {
SNDERR("Invalid type for %s", id);
goto _err;
}
continue;
}
SNDERR("Unknown field %s", id);
err = -EINVAL;
goto _err;
}
}
if (!open_name) {
open_name = buf;
snprintf(buf, sizeof(buf), "_snd_pcm_%s_open", str);
}
#ifndef PIC
snd_pcm_open_symbols(); /* this call is for static linking only */
#endif
h = snd_dlopen(lib, RTLD_NOW);
if (h)
open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_PCM_DLSYM_VERSION));
err = 0;
if (!h) {
SNDERR("Cannot open shared library %s", lib);
err = -ENOENT;
} else if (!open_func) {
SNDERR("symbol %s is not defined inside %s", open_name, lib);
snd_dlclose(h);
err = -ENXIO;
}
_err:
if (type_conf)
snd_config_delete(type_conf);
return err >= 0 ? open_func(pcmp, name, pcm_root, pcm_conf, stream, mode) : err;
}
static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root,
const char *name, snd_pcm_stream_t stream, int mode)
{
int err;
snd_config_t *pcm_conf;
err = snd_config_search_definition(root, "pcm", name, &pcm_conf);
if (err < 0) {
SNDERR("Unknown PCM %s", name);
return err;
}
err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode);
snd_config_delete(pcm_conf);
return err;
}
/**
* \brief Opens a PCM
* \param pcmp Returned PCM handle
* \param name ASCII identifier of the PCM handle
* \param stream Wanted stream
* \param mode Open mode (see #SND_PCM_NONBLOCK, #SND_PCM_ASYNC)
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_open(snd_pcm_t **pcmp, const char *name,
snd_pcm_stream_t stream, int mode)
{
int err;
assert(pcmp && name);
err = snd_config_update();
if (err < 0)
return err;
return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode);
}
#ifndef DOC_HIDDEN
int snd_pcm_new(snd_pcm_t **pcmp, snd_pcm_type_t type, const char *name,
snd_pcm_stream_t stream, int mode)
{
snd_pcm_t *pcm;
pcm = calloc(1, sizeof(*pcm));
if (!pcm)
return -ENOMEM;
pcm->type = type;
if (name)
pcm->name = strdup(name);
pcm->stream = stream;
pcm->mode = mode;
pcm->op_arg = pcm;
pcm->fast_op_arg = pcm;
INIT_LIST_HEAD(&pcm->async_handlers);
*pcmp = pcm;
return 0;
}
int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
snd_config_t *conf, snd_pcm_stream_t stream,
int mode)
{
const char *str;
if (snd_config_get_string(conf, &str) >= 0)
return snd_pcm_open_noupdate(pcmp, root, str, stream, mode);
return snd_pcm_open_conf(pcmp, NULL, root, conf, stream, mode);
}
#endif
/**
* \brief Wait for a PCM to become ready
* \param pcm PCM handle
* \param timeout maximum time in milliseconds to wait
* \return a positive value on success otherwise a negative error code
* \retval 0 timeout occured
* \retval 1 PCM stream is ready for I/O
*/
int snd_pcm_wait(snd_pcm_t *pcm, int timeout)
{
struct pollfd pfd;
int err;
err = snd_pcm_poll_descriptors(pcm, &pfd, 1);
assert(err == 1);
err = poll(&pfd, 1, timeout);
if (err < 0)
return -errno;
return err > 0 ? 1 : 0;
}
/**
* \brief Return number of frames ready to be read/written
* \param pcm PCM handle
* \return a positive number of frames ready otherwise a negative
* error code
*
* On capture does all the actions needed to transport to application
* level all the ready frames across underlying layers.
*/
snd_pcm_sframes_t snd_pcm_avail_update(snd_pcm_t *pcm)
{
return pcm->fast_ops->avail_update(pcm->fast_op_arg);
}
/**
* \brief Silence an area
* \param dst_area area specification
* \param dst_offset offset in frames inside area
* \param samples samples to silence
* \param format PCM sample format
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t dst_offset,
unsigned int samples, snd_pcm_format_t format)
{
/* FIXME: sub byte resolution and odd dst_offset */
char *dst;
unsigned int dst_step;
int width;
u_int64_t silence;
if (!dst_area->addr)
return 0;
dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
width = snd_pcm_format_physical_width(format);
silence = snd_pcm_format_silence_64(format);
if (dst_area->step == (unsigned int) width) {
unsigned int dwords = samples * width / 64;
samples -= dwords * 64 / width;
while (dwords-- > 0)
*((u_int64_t*)dst)++ = silence;
if (samples == 0)
return 0;
}
dst_step = dst_area->step / 8;
switch (width) {
case 4: {
u_int8_t s0 = silence & 0xf0;
u_int8_t s1 = silence & 0x0f;
int dstbit = dst_area->first % 8;
int dstbit_step = dst_area->step % 8;
while (samples-- > 0) {
if (dstbit) {
*dst &= 0xf0;
*dst |= s1;
} else {
*dst &= 0x0f;
*dst |= s0;
}
dst += dst_step;
dstbit += dstbit_step;
if (dstbit == 8) {
dst++;
dstbit = 0;
}
}
break;
}
case 8: {
u_int8_t sil = silence;
while (samples-- > 0) {
*dst = sil;
dst += dst_step;
}
break;
}
case 16: {
u_int16_t sil = silence;
while (samples-- > 0) {
*(u_int16_t*)dst = sil;
dst += dst_step;
}
break;
}
case 32: {
u_int32_t sil = silence;
while (samples-- > 0) {
*(u_int32_t*)dst = sil;
dst += dst_step;
}
break;
}
case 64: {
while (samples-- > 0) {
*(u_int64_t*)dst = silence;
dst += dst_step;
}
break;
}
default:
assert(0);
}
return 0;
}
/**
* \brief Silence one or more areas
* \param dst_areas areas specification (one for each channel)
* \param dst_offset offset in frames inside area
* \param channels channels count
* \param frames frames to silence
* \param format PCM sample format
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_areas_silence(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format)
{
int width = snd_pcm_format_physical_width(format);
while (channels > 0) {
void *addr = dst_areas->addr;
unsigned int step = dst_areas->step;
const snd_pcm_channel_area_t *begin = dst_areas;
int channels1 = channels;
unsigned int chns = 0;
int err;
while (1) {
channels1--;
chns++;
dst_areas++;
if (channels1 == 0 ||
dst_areas->addr != addr ||
dst_areas->step != step ||
dst_areas->first != dst_areas[-1].first + width)
break;
}
if (chns > 1 && chns * width == step) {
/* Collapse the areas */
snd_pcm_channel_area_t d;
d.addr = begin->addr;
d.first = begin->first;
d.step = width;
err = snd_pcm_area_silence(&d, dst_offset * chns, frames * chns, format);
channels -= chns;
} else {
err = snd_pcm_area_silence(begin, dst_offset, frames, format);
dst_areas = begin + 1;
channels--;
}
if (err < 0)
return err;
}
return 0;
}
/**
* \brief Copy an area
* \param dst_area destination area specification
* \param dst_offset offset in frames inside destination area
* \param src_area source area specification
* \param src_offset offset in frames inside source area
* \param samples samples to copy
* \param format PCM sample format
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t dst_offset,
const snd_pcm_channel_area_t *src_area, snd_pcm_uframes_t src_offset,
unsigned int samples, snd_pcm_format_t format)
{
/* FIXME: sub byte resolution and odd dst_offset */
const char *src;
char *dst;
int width;
int src_step, dst_step;
if (!src_area->addr)
return snd_pcm_area_silence(dst_area, dst_offset, samples, format);
src = snd_pcm_channel_area_addr(src_area, src_offset);
if (!dst_area->addr)
return 0;
dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
width = snd_pcm_format_physical_width(format);
if (src_area->step == (unsigned int) width &&
dst_area->step == (unsigned int) width) {
size_t bytes = samples * width / 8;
samples -= bytes * 8 / width;
memcpy(dst, src, bytes);
if (samples == 0)
return 0;
}
src_step = src_area->step / 8;
dst_step = dst_area->step / 8;
switch (width) {
case 4: {
int srcbit = src_area->first % 8;
int srcbit_step = src_area->step % 8;
int dstbit = dst_area->first % 8;
int dstbit_step = dst_area->step % 8;
while (samples-- > 0) {
unsigned char srcval;
if (srcbit)
srcval = *src & 0x0f;
else
srcval = *src & 0xf0;
if (dstbit)
*dst &= 0xf0;
else
*dst &= 0x0f;
*dst |= srcval;
src += src_step;
srcbit += srcbit_step;
if (srcbit == 8) {
src++;
srcbit = 0;
}
dst += dst_step;
dstbit += dstbit_step;
if (dstbit == 8) {
dst++;
dstbit = 0;
}
}
break;
}
case 8: {
while (samples-- > 0) {
*dst = *src;
src += src_step;
dst += dst_step;
}
break;
}
case 16: {
while (samples-- > 0) {
*(u_int16_t*)dst = *(const u_int16_t*)src;
src += src_step;
dst += dst_step;
}
break;
}
case 32: {
while (samples-- > 0) {
*(u_int32_t*)dst = *(const u_int32_t*)src;
src += src_step;
dst += dst_step;
}
break;
}
case 64: {
while (samples-- > 0) {
*(u_int64_t*)dst = *(const u_int64_t*)src;
src += src_step;
dst += dst_step;
}
break;
}
default:
assert(0);
}
return 0;
}
/**
* \brief Copy one or more areas
* \param dst_areas destination areas specification (one for each channel)
* \param dst_offset offset in frames inside destination area
* \param src_areas source areas specification (one for each channel)
* \param src_offset offset in frames inside source area
* \param channels channels count
* \param frames frames to copy
* \param format PCM sample format
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format)
{
int width = snd_pcm_format_physical_width(format);
assert(dst_areas);
assert(src_areas);
assert(channels > 0);
assert(frames > 0);
while (channels > 0) {
unsigned int step = src_areas->step;
void *src_addr = src_areas->addr;
const snd_pcm_channel_area_t *src_start = src_areas;
void *dst_addr = dst_areas->addr;
const snd_pcm_channel_area_t *dst_start = dst_areas;
int channels1 = channels;
unsigned int chns = 0;
while (dst_areas->step == step) {
channels1--;
chns++;
src_areas++;
dst_areas++;
if (channels1 == 0 ||
src_areas->step != step ||
src_areas->addr != src_addr ||
dst_areas->addr != dst_addr ||
src_areas->first != src_areas[-1].first + width ||
dst_areas->first != dst_areas[-1].first + width)
break;
}
if (chns > 1 && chns * width == step) {
/* Collapse the areas */
snd_pcm_channel_area_t s, d;
s.addr = src_start->addr;
s.first = src_start->first;
s.step = width;
d.addr = dst_start->addr;
d.first = dst_start->first;
d.step = width;
snd_pcm_area_copy(&d, dst_offset * chns,
&s, src_offset * chns,
frames * chns, format);
channels -= chns;
} else {
snd_pcm_area_copy(dst_start, dst_offset,
src_start, src_offset,
frames, format);
src_areas = src_start + 1;
dst_areas = dst_start + 1;
channels--;
}
}
return 0;
}
/**
* \brief Dump a PCM hardware configuration space
* \param params Configuration space
* \param out Output handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_hw_params_dump(snd_pcm_hw_params_t *params, snd_output_t *out)
{
unsigned int k;
for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++) {
snd_output_printf(out, "%s: ", snd_pcm_hw_param_name(k));
snd_pcm_hw_param_dump(params, k, out);
snd_output_putc(out, '\n');
}
return 0;
}
/**
* \brief Check, if hardware supports sample-resolution mmap for given configuration
* \param param Configuration space
* \return Boolean value
* \retval 0 Hardware doesn't support sample-resolution mmap
* \retval 1 Hardware supports sample-resolution mmap
*/
int snd_pcm_hw_params_can_mmap_sample_resolution(const snd_pcm_hw_params_t *params)
{
assert(params);
return !!(params->info & SNDRV_PCM_INFO_MMAP_VALID);
}
/**
* \brief Check, if hardware does double buffering for start/stop for given configuration
* \param param Configuration space
* \return Boolean value
* \retval 0 Hardware doesn't do double buffering for start/stop
* \retval 1 Hardware does double buffering for start/stop
*/
int snd_pcm_hw_params_is_double(const snd_pcm_hw_params_t *params)
{
assert(params);
return !!(params->info & SNDRV_PCM_INFO_DOUBLE);
}
/**
* \brief Check, if hardware does double buffering for data transfers for given configuration
* \param param Configuration space
* \return Boolean value
* \retval 0 Hardware doesn't do double buffering for data transfers
* \retval 1 Hardware does double buffering for data transfers
*/
int snd_pcm_hw_params_is_batch(const snd_pcm_hw_params_t *params)
{
assert(params);
return !!(params->info & SNDRV_PCM_INFO_BATCH);
}
/**
* \brief Check, if hardware does block transfers for samples for given configuration
* \param param Configuration space
* \return Boolean value
* \retval 0 Hardware doesn't block transfers
* \retval 1 Hardware does block transfers
*/
int snd_pcm_hw_params_is_block_transfer(const snd_pcm_hw_params_t *params)
{
assert(params);
return !!(params->info & SNDRV_PCM_INFO_BLOCK_TRANSFER);
}
/**
* \brief Check, if hardware supports overrange detection
* \param param Configuration space
* \return Boolean value
* \retval 0 Hardware doesn't support overrange detection
* \retval 1 Hardware supports overrange detection
*/
int snd_pcm_hw_params_can_overrange(const snd_pcm_hw_params_t *params)
{
assert(params);
return !!(params->info & SNDRV_PCM_INFO_OVERRANGE);
}
/**
* \brief Check, if hardware supports pause
* \param param Configuration space
* \return Boolean value
* \retval 0 Hardware doesn't support pause
* \retval 1 Hardware supports pause
*/
int snd_pcm_hw_params_can_pause(const snd_pcm_hw_params_t *params)
{
assert(params);
return !!(params->info & SNDRV_PCM_INFO_PAUSE);
}
/**
* \brief Check, if hardware supports resume
* \param param Configuration space
* \return Boolean value
* \retval 0 Hardware doesn't support resume
* \retval 1 Hardware supports resume
*/
int snd_pcm_hw_params_can_resume(const snd_pcm_hw_params_t *params)
{
assert(params);
return !!(params->info & SNDRV_PCM_INFO_RESUME);
}
/**
* \brief Check, if hardware does half-duplex only
* \param param Configuration space
* \return Boolean value
* \retval 0 Hardware doesn't do half-duplex
* \retval 1 Hardware does half-duplex
*/
int snd_pcm_hw_params_is_half_duplex(const snd_pcm_hw_params_t *params)
{
assert(params);
return !!(params->info & SNDRV_PCM_INFO_HALF_DUPLEX);
}
/**
* \brief Check, if hardware does joint-duplex (playback and capture are somewhat correlated)
* \param param Configuration space
* \return Boolean value
* \retval 0 Hardware doesn't do joint-duplex
* \retval 1 Hardware does joint-duplex
*/
int snd_pcm_hw_params_is_joint_duplex(const snd_pcm_hw_params_t *params)
{
assert(params);
return !!(params->info & SNDRV_PCM_INFO_JOINT_DUPLEX);
}
/**
* \brief Check, if hardware supports synchronized start with sample resolution
* \param param Configuration space
* \return Boolean value
* \retval 0 Hardware doesn't support synchronized start
* \retval 1 Hardware supports synchronized start
*/
int snd_pcm_hw_params_can_sync_start(const snd_pcm_hw_params_t *params)
{
assert(params);
return !!(params->info & SNDRV_PCM_INFO_SYNC_START);
}
/**
* \brief Get rate exact info from a configuration space
* \param params Configuration space
* \param rate_num Pointer to returned rate numerator
* \param rate_den Pointer to returned rate denominator
* \return 0 otherwise a negative error code if the info is not available
*/
int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params,
unsigned int *rate_num, unsigned int *rate_den)
{
if (params->rate_den == 0)
return -EINVAL;
*rate_num = params->rate_num;
*rate_den = params->rate_den;
return 0;
}
/**
* \brief Get sample resolution info from a configuration space
* \param params Configuration space
* \return significative bits in sample otherwise a negative error code if the info is not available
*/
int snd_pcm_hw_params_get_sbits(const snd_pcm_hw_params_t *params)
{
if (params->msbits == 0)
return -EINVAL;
return params->msbits;
}
/**
* \brief Get hardare fifo size info from a configuration space
* \param params Configuration space
* \return fifo size in frames otherwise a negative error code if the info is not available
*/
int snd_pcm_hw_params_get_fifo_size(const snd_pcm_hw_params_t *params)
{
if (params->fifo_size == 0)
return -EINVAL;
return params->fifo_size;
}
/**
* \brief Fill params with a full configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
*/
int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
_snd_pcm_hw_params_any(params);
return snd_pcm_hw_refine(pcm, params);
}
/**
* \brief get size of #snd_pcm_access_mask_t
* \return size in bytes
*/
size_t snd_pcm_access_mask_sizeof()
{
return sizeof(snd_pcm_access_mask_t);
}
/**
* \brief allocate an empty #snd_pcm_access_mask_t using standard malloc
* \param ptr returned pointer
* \return 0 on success otherwise negative error code
*/
int snd_pcm_access_mask_malloc(snd_pcm_access_mask_t **ptr)
{
assert(ptr);
*ptr = calloc(1, sizeof(snd_pcm_access_mask_t));
if (!*ptr)
return -ENOMEM;
return 0;
}
/**
* \brief frees a previously allocated #snd_pcm_access_mask_t
* \param pointer to object to free
*/
void snd_pcm_access_mask_free(snd_pcm_access_mask_t *obj)
{
free(obj);
}
/**
* \brief copy one #snd_pcm_access_mask_t to another
* \param dst pointer to destination
* \param src pointer to source
*/
void snd_pcm_access_mask_copy(snd_pcm_access_mask_t *dst, const snd_pcm_access_mask_t *src)
{
assert(dst && src);
*dst = *src;
}
/**
* \brief reset all bits in a #snd_pcm_access_mask_t
* \param mask pointer to mask
*/
void snd_pcm_access_mask_none(snd_pcm_access_mask_t *mask)
{
snd_mask_none((snd_mask_t *) mask);
}
/**
* \brief set all bits in a #snd_pcm_access_mask_t
* \param mask pointer to mask
*/
void snd_pcm_access_mask_any(snd_pcm_access_mask_t *mask)
{
snd_mask_any((snd_mask_t *) mask);
}
/**
* \brief test the presence of an access type in a #snd_pcm_access_mask_t
* \param mask pointer to mask
* \param val access type
*/
int snd_pcm_access_mask_test(const snd_pcm_access_mask_t *mask, snd_pcm_access_t val)
{
return snd_mask_test((const snd_mask_t *) mask, (unsigned long) val);
}
/**
* \brief make an access type present in a #snd_pcm_access_mask_t
* \param mask pointer to mask
* \param val access type
*/
void snd_pcm_access_mask_set(snd_pcm_access_mask_t *mask, snd_pcm_access_t val)
{
snd_mask_set((snd_mask_t *) mask, (unsigned long) val);
}
/**
* \brief make an access type missing from a #snd_pcm_access_mask_t
* \param mask pointer to mask
* \param val access type
*/
void snd_pcm_access_mask_reset(snd_pcm_access_mask_t *mask, snd_pcm_access_t val)
{
snd_mask_reset((snd_mask_t *) mask, (unsigned long) val);
}
/**
* \brief get size of #snd_pcm_format_mask_t
* \return size in bytes
*/
size_t snd_pcm_format_mask_sizeof()
{
return sizeof(snd_pcm_format_mask_t);
}
/**
* \brief allocate an empty #snd_pcm_format_mask_t using standard malloc
* \param ptr returned pointer
* \return 0 on success otherwise negative error code
*/
int snd_pcm_format_mask_malloc(snd_pcm_format_mask_t **ptr)
{
assert(ptr);
*ptr = calloc(1, sizeof(snd_pcm_format_mask_t));
if (!*ptr)
return -ENOMEM;
return 0;
}
/**
* \brief frees a previously allocated #snd_pcm_format_mask_t
* \param pointer to object to free
*/
void snd_pcm_format_mask_free(snd_pcm_format_mask_t *obj)
{
free(obj);
}
/**
* \brief copy one #snd_pcm_format_mask_t to another
* \param dst pointer to destination
* \param src pointer to source
*/
void snd_pcm_format_mask_copy(snd_pcm_format_mask_t *dst, const snd_pcm_format_mask_t *src)
{
assert(dst && src);
*dst = *src;
}
/**
* \brief reset all bits in a #snd_pcm_format_mask_t
* \param mask pointer to mask
*/
void snd_pcm_format_mask_none(snd_pcm_format_mask_t *mask)
{
snd_mask_none((snd_mask_t *) mask);
}
/**
* \brief set all bits in a #snd_pcm_format_mask_t
* \param mask pointer to mask
*/
void snd_pcm_format_mask_any(snd_pcm_format_mask_t *mask)
{
snd_mask_any((snd_mask_t *) mask);
}
/**
* \brief test the presence of a format in a #snd_pcm_format_mask_t
* \param mask pointer to mask
* \param val format
*/
int snd_pcm_format_mask_test(const snd_pcm_format_mask_t *mask, snd_pcm_format_t val)
{
return snd_mask_test((const snd_mask_t *) mask, (unsigned long) val);
}
/**
* \brief make a format present in a #snd_pcm_format_mask_t
* \param mask pointer to mask
* \param val format
*/
void snd_pcm_format_mask_set(snd_pcm_format_mask_t *mask, snd_pcm_format_t val)
{
snd_mask_set((snd_mask_t *) mask, (unsigned long) val);
}
/**
* \brief make a format missing from a #snd_pcm_format_mask_t
* \param mask pointer to mask
* \param val format
*/
void snd_pcm_format_mask_reset(snd_pcm_format_mask_t *mask, snd_pcm_format_t val)
{
snd_mask_reset((snd_mask_t *) mask, (unsigned long) val);
}
/**
* \brief get size of #snd_pcm_subformat_mask_t
* \return size in bytes
*/
size_t snd_pcm_subformat_mask_sizeof()
{
return sizeof(snd_pcm_subformat_mask_t);
}
/**
* \brief allocate an empty #snd_pcm_subformat_mask_t using standard malloc
* \param ptr returned pointer
* \return 0 on success otherwise negative error code
*/
int snd_pcm_subformat_mask_malloc(snd_pcm_subformat_mask_t **ptr)
{
assert(ptr);
*ptr = calloc(1, sizeof(snd_pcm_subformat_mask_t));
if (!*ptr)
return -ENOMEM;
return 0;
}
/**
* \brief frees a previously allocated #snd_pcm_subformat_mask_t
* \param pointer to object to free
*/
void snd_pcm_subformat_mask_free(snd_pcm_subformat_mask_t *obj)
{
free(obj);
}
/**
* \brief copy one #snd_pcm_subformat_mask_t to another
* \param dst pointer to destination
* \param src pointer to source
*/
void snd_pcm_subformat_mask_copy(snd_pcm_subformat_mask_t *dst, const snd_pcm_subformat_mask_t *src)
{
assert(dst && src);
*dst = *src;
}
/**
* \brief reset all bits in a #snd_pcm_subformat_mask_t
* \param mask pointer to mask
*/
void snd_pcm_subformat_mask_none(snd_pcm_subformat_mask_t *mask)
{
snd_mask_none((snd_mask_t *) mask);
}
/**
* \brief set all bits in a #snd_pcm_subformat_mask_t
* \param mask pointer to mask
*/
void snd_pcm_subformat_mask_any(snd_pcm_subformat_mask_t *mask)
{
snd_mask_any((snd_mask_t *) mask);
}
/**
* \brief test the presence of a subformat in a #snd_pcm_subformat_mask_t
* \param mask pointer to mask
* \param val subformat
*/
int snd_pcm_subformat_mask_test(const snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val)
{
return snd_mask_test((const snd_mask_t *) mask, (unsigned long) val);
}
/**
* \brief make a subformat present in a #snd_pcm_subformat_mask_t
* \param mask pointer to mask
* \param val subformat
*/
void snd_pcm_subformat_mask_set(snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val)
{
snd_mask_set((snd_mask_t *) mask, (unsigned long) val);
}
/**
* \brief make a subformat missing from a #snd_pcm_subformat_mask_t
* \param mask pointer to mask
* \param val subformat
*/
void snd_pcm_subformat_mask_reset(snd_pcm_subformat_mask_t *mask, snd_pcm_subformat_t val)
{
snd_mask_reset((snd_mask_t *) mask, (unsigned long) val);
}
/**
* \brief get size of #snd_pcm_hw_params_t
* \return size in bytes
*/
size_t snd_pcm_hw_params_sizeof()
{
return sizeof(snd_pcm_hw_params_t);
}
/**
* \brief allocate an invalid #snd_pcm_hw_params_t using standard malloc
* \param ptr returned pointer
* \return 0 on success otherwise negative error code
*/
int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr)
{
assert(ptr);
*ptr = calloc(1, sizeof(snd_pcm_hw_params_t));
if (!*ptr)
return -ENOMEM;
return 0;
}
/**
* \brief frees a previously allocated #snd_pcm_hw_params_t
* \param pointer to object to free
*/
void snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj)
{
free(obj);
}
/**
* \brief copy one #snd_pcm_hw_params_t to another
* \param dst pointer to destination
* \param src pointer to source
*/
void snd_pcm_hw_params_copy(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src)
{
assert(dst && src);
*dst = *src;
}
/**
* \brief Extract access type from a configuration space
* \param params Configuration space
* \return access type otherwise a negative error code if not exactly one is present
*/
int snd_pcm_hw_params_get_access(const snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_ACCESS, NULL);
}
/**
* \brief Verify if an access type is available inside a configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
* \param val access type
* \return 1 if available 0 otherwise
*/
int snd_pcm_hw_params_test_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t val)
{
return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_ACCESS, val, 0);
}
/**
* \brief Restrict a configuration space to contain only one access type
* \param pcm PCM handle
* \param params Configuration space
* \param val access type
* \return 0 otherwise a negative error code if configuration space would become empty
*/
int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t val)
{
return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_ACCESS, val, 0);
}
/**
* \brief Restrict a configuration space to contain only its first access type
* \param pcm PCM handle
* \param params Configuration space
* \return access type
*/
snd_pcm_access_t snd_pcm_hw_params_set_access_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, NULL);
}
/**
* \brief Restrict a configuration space to contain only its last access type
* \param pcm PCM handle
* \param params Configuration space
* \return access type
*/
snd_pcm_access_t snd_pcm_hw_params_set_access_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_ACCESS, NULL);
}
/**
* \brief Restrict a configuration space to contain only a set of access types
* \param pcm PCM handle
* \param params Configuration space
* \param mask Access mask
* \return access type
*/
int snd_pcm_hw_params_set_access_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask)
{
return snd_pcm_hw_param_set_mask(pcm, params, SND_TRY, SND_PCM_HW_PARAM_ACCESS, (snd_mask_t *) mask);
}
/**
* \brief Get access mask from a configuration space
* \param params Configuration space
* \param mask Returned Access mask
*/
void snd_pcm_hw_params_get_access_mask(snd_pcm_hw_params_t *params, snd_pcm_access_mask_t *mask)
{
snd_pcm_access_mask_copy(mask, snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS));
}
/**
* \brief Extract format from a configuration space
* \param params Configuration space
* \return format otherwise a negative error code if not exactly one is present
*/
int snd_pcm_hw_params_get_format(const snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_FORMAT, NULL);
}
/**
* \brief Verify if a format is available inside a configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
* \param val format
* \return 1 if available 0 otherwise
*/
int snd_pcm_hw_params_test_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val)
{
return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_FORMAT, val, 0);
}
/**
* \brief Restrict a configuration space to contain only one format
* \param pcm PCM handle
* \param params Configuration space
* \param val format
* \return 0 otherwise a negative error code if configuration space would become empty
*/
int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val)
{
return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_FORMAT, val, 0);
}
/**
* \brief Restrict a configuration space to contain only its first format
* \param pcm PCM handle
* \param params Configuration space
* \return format
*/
snd_pcm_format_t snd_pcm_hw_params_set_format_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, NULL);
}
/**
* \brief Restrict a configuration space to contain only its last format
* \param pcm PCM handle
* \param params Configuration space
* \return format
*/
snd_pcm_format_t snd_pcm_hw_params_set_format_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_FORMAT, NULL);
}
/**
* \brief Restrict a configuration space to contain only a set of formats
* \param pcm PCM handle
* \param params Configuration space
* \param mask Format mask
* \return access type
*/
int snd_pcm_hw_params_set_format_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask)
{
return snd_pcm_hw_param_set_mask(pcm, params, SND_TRY, SND_PCM_HW_PARAM_FORMAT, (snd_mask_t *) mask);
}
/**
* \brief Get format mask from a configuration space
* \param params Configuration space
* \param mask Returned Format mask
*/
void snd_pcm_hw_params_get_format_mask(snd_pcm_hw_params_t *params, snd_pcm_format_mask_t *mask)
{
snd_pcm_format_mask_copy(mask, snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_FORMAT));
}
/**
* \brief Verify if a subformat is available inside a configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
* \param val subformat
* \return 1 if available 0 otherwise
*/
int snd_pcm_hw_params_test_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t val)
{
return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_SUBFORMAT, val, 0);
}
/**
* \brief Extract subformat from a configuration space
* \param params Configuration space
* \return subformat otherwise a negative error code if not exactly one is present
*/
int snd_pcm_hw_params_get_subformat(const snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_SUBFORMAT, NULL);
}
/**
* \brief Restrict a configuration space to contain only one subformat
* \param pcm PCM handle
* \param params Configuration space
* \param val subformat
* \return 0 otherwise a negative error code if configuration space would become empty
*/
int snd_pcm_hw_params_set_subformat(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_t val)
{
return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_SUBFORMAT, val, 0);
}
/**
* \brief Restrict a configuration space to contain only its first subformat
* \param pcm PCM handle
* \param params Configuration space
* \return subformat
*/
snd_pcm_subformat_t snd_pcm_hw_params_set_subformat_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, NULL);
}
/**
* \brief Restrict a configuration space to contain only its last subformat
* \param pcm PCM handle
* \param params Configuration space
* \return subformat
*/
snd_pcm_subformat_t snd_pcm_hw_params_set_subformat_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, NULL);
}
/**
* \brief Restrict a configuration space to contain only a set of subformats
* \param pcm PCM handle
* \param params Configuration space
* \param mask Subformat mask
* \return access type
*/
int snd_pcm_hw_params_set_subformat_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask)
{
return snd_pcm_hw_param_set_mask(pcm, params, SND_TRY, SND_PCM_HW_PARAM_SUBFORMAT, (snd_mask_t *) mask);
}
/**
* \brief Get subformat mask from a configuration space
* \param params Configuration space
* \param mask Returned Subformat mask
*/
void snd_pcm_hw_params_get_subformat_mask(snd_pcm_hw_params_t *params, snd_pcm_subformat_mask_t *mask)
{
snd_pcm_subformat_mask_copy(mask, snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_SUBFORMAT));
}
/**
* \brief Extract channels from a configuration space
* \param params Configuration space
* \return channels count otherwise a negative error code if not exactly one is present
*/
int snd_pcm_hw_params_get_channels(const snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_CHANNELS, NULL);
}
/**
* \brief Extract minimum channels count from a configuration space
* \param params Configuration space
* \return minimum channels count
*/
unsigned int snd_pcm_hw_params_get_channels_min(const snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_CHANNELS, NULL);
}
/**
* \brief Extract maximum channels count from a configuration space
* \param params Configuration space
* \return maximum channels count
*/
unsigned int snd_pcm_hw_params_get_channels_max(const snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_CHANNELS, NULL);
}
/**
* \brief Verify if a channels count is available inside a configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
* \param val channels count
* \return 1 if available 0 otherwise
*/
int snd_pcm_hw_params_test_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val)
{
return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_CHANNELS, val, 0);
}
/**
* \brief Restrict a configuration space to contain only one channels count
* \param pcm PCM handle
* \param params Configuration space
* \param val channels count
* \return 0 otherwise a negative error code if configuration space would become empty
*/
int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val)
{
return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_CHANNELS, val, 0);
}
/**
* \brief Restrict a configuration space with a minimum channels count
* \param pcm PCM handle
* \param params Configuration space
* \param val minimum channels count (on return filled with actual minimum)
* \return 0 otherwise a negative error code if configuration space would become empty
*/
int snd_pcm_hw_params_set_channels_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val)
{
return snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_CHANNELS, val, NULL);
}
/**
* \brief Restrict a configuration space with a maximum channels count
* \param pcm PCM handle
* \param params Configuration space
* \param val maximum channels count (on return filled with actual maximum)
* \return 0 otherwise a negative error code if configuration space would become empty
*/
int snd_pcm_hw_params_set_channels_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val)
{
return snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_CHANNELS, val, NULL);
}
/**
* \brief Restrict a configuration space to have channels counts in a given range
* \param pcm PCM handle
* \param params Configuration space
* \param min minimum channels count (on return filled with actual minimum)
* \param max maximum channels count (on return filled with actual maximum)
* \return 0 otherwise a negative error code if configuration space would become empty
*/
int snd_pcm_hw_params_set_channels_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, unsigned int *max)
{
return snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_CHANNELS, min, NULL, max, NULL);
}
/**
* \brief Restrict a configuration space to have channels count nearest to a target
* \param pcm PCM handle
* \param params Configuration space
* \param val target channels count
* \return choosen channels count
*/
unsigned int snd_pcm_hw_params_set_channels_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val)
{
return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_CHANNELS, val, NULL);
}
/**
* \brief Restrict a configuration space to contain only its minimum channels count
* \param pcm PCM handle
* \param params Configuration space
* \return channels count
*/
unsigned int snd_pcm_hw_params_set_channels_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, NULL);
}
/**
* \brief Restrict a configuration space to contain only its maximum channels count
* \param pcm PCM handle
* \param params Configuration space
* \return channels count
*/
unsigned int snd_pcm_hw_params_set_channels_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_CHANNELS, NULL);
}
/**
* \brief Extract rate from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate rate otherwise a negative error code if not exactly one is present
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
int snd_pcm_hw_params_get_rate(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_RATE, dir);
}
/**
* \brief Extract minimum rate from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate minimum rate
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_get_rate_min(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_RATE, dir);
}
/**
* \brief Extract maximum rate from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate maximum rate
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_get_rate_max(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_RATE, dir);
}
/**
* \brief Verify if a rate is available inside a configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate rate
* \param dir Sub unit direction
* \return 1 if available 0 otherwise
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_test_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_RATE, val, dir);
}
/**
* \brief Restrict a configuration space to contain only one rate
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate rate
* \param dir Sub unit direction
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_RATE, val, dir);
}
/**
* \brief Restrict a configuration space with a minimum rate
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate minimum rate (on return filled with actual minimum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact minimum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_rate_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
{
return snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_RATE, val, dir);
}
/**
* \brief Restrict a configuration space with a maximum rate
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate maximum rate (on return filled with actual maximum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact maximum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_rate_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
{
return snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_RATE, val, dir);
}
/**
* \brief Restrict a configuration space to have rates in a given range
* \param pcm PCM handle
* \param params Configuration space
* \param min approximate minimum rate (on return filled with actual minimum)
* \param mindir Sub unit direction for minimum (on return filled with actual direction)
* \param max approximate maximum rate (on return filled with actual maximum)
* \param maxdir Sub unit direction for maximum (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact min/max is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_rate_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir)
{
return snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_RATE, min, mindir, max, maxdir);
}
/**
* \brief Restrict a configuration space to have rate nearest to a target
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate target rate
* \return approximate choosen rate
*
* target/choosen exact value is <,=,> val following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir)
{
return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_RATE, val, dir);
}
/**
* \brief Restrict a configuration space to contain only its minimum rate
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate rate
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
unsigned int snd_pcm_hw_params_set_rate_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_RATE, dir);
}
/**
* \brief Restrict a configuration space to contain only its maximum rate
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate rate
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
unsigned int snd_pcm_hw_params_set_rate_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_RATE, dir);
}
/**
* \brief Extract period time from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate period duration in us otherwise a negative error code if not exactly one is present
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
int snd_pcm_hw_params_get_period_time(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIOD_TIME, dir);
}
/**
* \brief Extract minimum period time from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate minimum period duration in us
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_get_period_time_min(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIOD_TIME, dir);
}
/**
* \brief Extract maximum period time from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate maximum period duration in us
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_get_period_time_max(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_PERIOD_TIME, dir);
}
/**
* \brief Verify if a period time is available inside a configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate period duration in us
* \param dir Sub unit direction
* \return 1 if available 0 otherwise
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_test_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir);
}
/**
* \brief Restrict a configuration space to contain only one period time
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate period duration in us
* \param dir Sub unit direction
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_period_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir);
}
/**
* \brief Restrict a configuration space with a minimum period time
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate minimum period duration in us (on return filled with actual minimum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact minimum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_period_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
{
return snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir);
}
/**
* \brief Restrict a configuration space with a maximum period time
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate maximum period duration in us (on return filled with actual maximum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact maximum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_period_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
{
return snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir);
}
/**
* \brief Restrict a configuration space to have period times in a given range
* \param pcm PCM handle
* \param params Configuration space
* \param min approximate minimum period duration in us (on return filled with actual minimum)
* \param mindir Sub unit direction for minimum (on return filled with actual direction)
* \param max approximate maximum period duration in us (on return filled with actual maximum)
* \param maxdir Sub unit direction for maximum (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact min/max is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_period_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir)
{
return snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_TIME, min, mindir, max, maxdir);
}
/**
* \brief Restrict a configuration space to have period time nearest to a target
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate target period duration in us
* \return approximate choosen period duration in us
*
* target/choosen exact value is <,=,> val following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_set_period_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir)
{
return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, val, dir);
}
/**
* \brief Restrict a configuration space to contain only its minimum period time
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate period duration in us
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
unsigned int snd_pcm_hw_params_set_period_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, dir);
}
/**
* \brief Restrict a configuration space to contain only its maximum period time
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate period duration in us
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
unsigned int snd_pcm_hw_params_set_period_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, dir);
}
/**
* \brief Extract period size from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate period size in frames otherwise a negative error code if not exactly one is present
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
snd_pcm_sframes_t snd_pcm_hw_params_get_period_size(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIOD_SIZE, dir);
}
/**
* \brief Extract minimum period size from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate minimum period size in frames
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
snd_pcm_uframes_t snd_pcm_hw_params_get_period_size_min(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIOD_SIZE, dir);
}
/**
* \brief Extract maximum period size from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate maximum period size in frames
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
snd_pcm_uframes_t snd_pcm_hw_params_get_period_size_max(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_PERIOD_SIZE, dir);
}
/**
* \brief Verify if a period size is available inside a configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate period size in frames
* \param dir Sub unit direction
* \return 1 if available 0 otherwise
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_test_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_PERIOD_SIZE, val, dir);
}
/**
* \brief Restrict a configuration space to contain only one period size
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate period size in frames
* \param dir Sub unit direction
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_period_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_SIZE, val, dir);
}
/**
* \brief Restrict a configuration space with a minimum period size
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate minimum period size in frames (on return filled with actual minimum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact minimum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_period_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)
{
unsigned int _val = *val;
int err = snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir);
*val = _val;
return err;
}
/**
* \brief Restrict a configuration space with a maximum period size
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate maximum period size in frames (on return filled with actual maximum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact minimum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_period_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)
{
unsigned int _val = *val;
int err = snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_SIZE, &_val, dir);
*val = _val;
return err;
}
/**
* \brief Restrict a configuration space to have period sizes in a given range
* \param pcm PCM handle
* \param params Configuration space
* \param min approximate minimum period size in frames (on return filled with actual minimum)
* \param mindir Sub unit direction for minimum (on return filled with actual direction)
* \param max approximate maximum period size in frames (on return filled with actual maximum)
* \param maxdir Sub unit direction for maximum (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact min/max is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_period_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, int *mindir, snd_pcm_uframes_t *max, int *maxdir)
{
unsigned int _min = *min;
unsigned int _max = *max;
int err = snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_SIZE, &_min, mindir, &_max, maxdir);
*min = _min;
*max = _max;
return err;
}
/**
* \brief Restrict a configuration space to have period size nearest to a target
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate target period size in frames
* \return approximate choosen period size in frames
*
* target/choosen exact value is <,=,> val following dir (-1,0,1)
*/
snd_pcm_uframes_t snd_pcm_hw_params_set_period_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int *dir)
{
return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, val, dir);
}
/**
* \brief Restrict a configuration space to contain only its minimum period size
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate period size in frames
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
snd_pcm_uframes_t snd_pcm_hw_params_set_period_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, dir);
}
/**
* \brief Restrict a configuration space to contain only its maximum period size
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate period size in frames
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
snd_pcm_uframes_t snd_pcm_hw_params_set_period_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, dir);
}
/**
* \brief Restrict a configuration space to contain only integer period sizes
* \param pcm PCM handle
* \param params Configuration space
* \return 0 otherwise a negative error code if configuration space would become empty
*/
int snd_pcm_hw_params_set_period_size_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_integer(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIOD_SIZE);
}
/**
* \brief Extract periods from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate periods per buffer otherwise a negative error code if not exactly one is present
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
int snd_pcm_hw_params_get_periods(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIODS, dir);
}
/**
* \brief Extract minimum periods count from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate minimum periods per buffer
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_get_periods_min(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIODS, dir);
}
/**
* \brief Extract maximum periods count from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate maximum periods per buffer
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_get_periods_max(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_PERIODS, dir);
}
/**
* \brief Verify if a periods count is available inside a configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate periods per buffer
* \param dir Sub unit direction
* \return 1 if available 0 otherwise
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_test_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_PERIODS, val, dir);
}
/**
* \brief Restrict a configuration space to contain only one periods count
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate periods per buffer
* \param dir Sub unit direction
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_periods(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIODS, val, dir);
}
/**
* \brief Restrict a configuration space with a minimum periods count
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate minimum periods per buffer (on return filled with actual minimum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact minimum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_periods_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
{
return snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIODS, val, dir);
}
/**
* \brief Restrict a configuration space with a maximum periods count
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate maximum periods per buffer (on return filled with actual maximum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact maximum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_periods_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
{
return snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIODS, val, dir);
}
/**
* \brief Restrict a configuration space to have periods counts in a given range
* \param pcm PCM handle
* \param params Configuration space
* \param min approximate minimum periods per buffer (on return filled with actual minimum)
* \param mindir Sub unit direction for minimum (on return filled with actual direction)
* \param max approximate maximum periods per buffer (on return filled with actual maximum)
* \param maxdir Sub unit direction for maximum (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact min/max is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_periods_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir)
{
return snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIODS, min, mindir, max, maxdir);
}
/**
* \brief Restrict a configuration space to have periods count nearest to a target
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate target periods per buffer
* \return approximate choosen periods per buffer
*
* target/choosen exact value is <,=,> val following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_set_periods_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir)
{
return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_PERIODS, val, dir);
}
/**
* \brief Restrict a configuration space to contain only its minimum periods count
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate periods per buffer
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
unsigned int snd_pcm_hw_params_set_periods_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIODS, dir);
}
/**
* \brief Restrict a configuration space to contain only its maximum periods count
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate periods per buffer
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
unsigned int snd_pcm_hw_params_set_periods_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_PERIODS, dir);
}
/**
* \brief Restrict a configuration space to contain only integer periods counts
* \param pcm PCM handle
* \param params Configuration space
* \return 0 otherwise a negative error code if configuration space would become empty
*/
int snd_pcm_hw_params_set_periods_integer(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_integer(pcm, params, SND_TRY, SND_PCM_HW_PARAM_PERIODS);
}
/**
* \brief Extract buffer time from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate buffer duration in us otherwise a negative error code if not exactly one is present
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
int snd_pcm_hw_params_get_buffer_time(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_BUFFER_TIME, dir);
}
/**
* \brief Extract minimum buffer time from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate minimum buffer duration in us
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_get_buffer_time_min(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_BUFFER_TIME, dir);
}
/**
* \brief Extract maximum buffer time from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate maximum buffer duration in us
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_get_buffer_time_max(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_BUFFER_TIME, dir);
}
/**
* \brief Verify if a buffer time is available inside a configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate buffer duration in us
* \param dir Sub unit direction
* \return 1 if available 0 otherwise
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_test_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir);
}
/**
* \brief Restrict a configuration space to contain only one buffer time
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate buffer duration in us
* \param dir Sub unit direction
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_buffer_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir);
}
/**
* \brief Restrict a configuration space with a minimum buffer time
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate minimum buffer duration in us (on return filled with actual minimum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact minimum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_buffer_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
{
return snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir);
}
/**
* \brief Restrict a configuration space with a maximum buffer time
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate maximum buffer duration in us (on return filled with actual maximum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact maximum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_buffer_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
{
return snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir);
}
/**
* \brief Restrict a configuration space to have buffer times in a given range
* \param pcm PCM handle
* \param params Configuration space
* \param min approximate minimum buffer duration in us (on return filled with actual minimum)
* \param mindir Sub unit direction for minimum (on return filled with actual direction)
* \param max approximate maximum buffer duration in us (on return filled with actual maximum)
* \param maxdir Sub unit direction for maximum (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact min/max is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_buffer_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir)
{
return snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_TIME, min, mindir, max, maxdir);
}
/**
* \brief Restrict a configuration space to have buffer time nearest to a target
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate target buffer duration in us
* \return approximate choosen buffer duration in us
*
* target/choosen exact value is <,=,> val following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_set_buffer_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir)
{
return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_BUFFER_TIME, val, dir);
}
/**
* \brief Restrict a configuration space to contain only its minimum buffer time
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate buffer duration in us
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
unsigned int snd_pcm_hw_params_set_buffer_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_BUFFER_TIME, dir);
}
/**
* \brief Restrict a configuration space to contain only its maximum bufferd time
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate buffer duration in us
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
unsigned int snd_pcm_hw_params_set_buffer_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_TIME, dir);
}
/**
* \brief Extract buffer size from a configuration space
* \param params Configuration space
* \return buffer size in frames otherwise a negative error code if not exactly one is present
*/
snd_pcm_sframes_t snd_pcm_hw_params_get_buffer_size(const snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL);
}
/**
* \brief Extract minimum buffer size from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate minimum buffer size in frames
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
snd_pcm_uframes_t snd_pcm_hw_params_get_buffer_size_min(const snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL);
}
/**
* \brief Extract maximum buffer size from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate maximum buffer size in frames
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
snd_pcm_uframes_t snd_pcm_hw_params_get_buffer_size_max(const snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL);
}
/**
* \brief Verify if a buffer size is available inside a configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
* \param val buffer size in frames
* \param dir Sub unit direction
* \return 1 if available 0 otherwise
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_test_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val)
{
return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_BUFFER_SIZE, val, 0);
}
/**
* \brief Restrict a configuration space to contain only one buffer size
* \param pcm PCM handle
* \param params Configuration space
* \param val buffer size in frames
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_buffer_size(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val)
{
return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_SIZE, val, 0);
}
/**
* \brief Restrict a configuration space with a minimum buffer size
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate minimum buffer size in frames (on return filled with actual minimum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact minimum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_buffer_size_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
{
unsigned int _val = *val;
int err = snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL);
*val = _val;
return err;
}
/**
* \brief Restrict a configuration space with a maximum buffer size
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate maximum buffer size in frames (on return filled with actual maximum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact minimum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_buffer_size_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
{
unsigned int _val = *val;
int err = snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_SIZE, &_val, NULL);
*val = _val;
return err;
}
/**
* \brief Restrict a configuration space to have buffer sizes in a given range
* \param pcm PCM handle
* \param params Configuration space
* \param min approximate minimum buffer size in frames (on return filled with actual minimum)
* \param mindir Sub unit direction for minimum (on return filled with actual direction)
* \param max approximate maximum buffer size in frames (on return filled with actual maximum)
* \param maxdir Sub unit direction for maximum (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact min/max is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_buffer_size_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *min, snd_pcm_uframes_t *max)
{
unsigned int _min = *min;
unsigned int _max = *max;
int err = snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_BUFFER_SIZE, &_min, NULL, &_max, NULL);
*min = _min;
*max = _max;
return err;
}
/**
* \brief Restrict a configuration space to have buffer size nearest to a target
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate target buffer size in frames
* \return approximate choosen buffer size in frames
*
* target/choosen exact value is <,=,> val following dir (-1,0,1)
*/
snd_pcm_uframes_t snd_pcm_hw_params_set_buffer_size_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val)
{
return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, val, NULL);
}
/**
* \brief Restrict a configuration space to contain only its minimum buffer size
* \param pcm PCM handle
* \param params Configuration space
* \return buffer size in frames
*/
snd_pcm_uframes_t snd_pcm_hw_params_set_buffer_size_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL);
}
/**
* \brief Restrict a configuration space to contain only its maximum buffer size
* \param pcm PCM handle
* \param params Configuration space
* \return buffer size in frames
*/
snd_pcm_uframes_t snd_pcm_hw_params_set_buffer_size_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL);
}
/**
* \brief Extract tick time from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate tick duration in us otherwise a negative error code if not exactly one is present
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
int snd_pcm_hw_params_get_tick_time(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_TICK_TIME, dir);
}
/**
* \brief Extract minimum tick time from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate minimum tick duration in us
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_get_tick_time_min(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_TICK_TIME, dir);
}
/**
* \brief Extract maximum tick time from a configuration space
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate maximum tick duration in us
*
* Exact value is <,=,> the returned one following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_get_tick_time_max(const snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_TICK_TIME, dir);
}
/**
* \brief Verify if a tick time is available inside a configuration space for a PCM
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate tick duration in us
* \param dir Sub unit direction
* \return 1 if available 0 otherwise
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_test_tick_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TEST, SND_PCM_HW_PARAM_TICK_TIME, val, dir);
}
/**
* \brief Restrict a configuration space to contain only one tick time
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate tick duration in us
* \param dir Sub unit direction
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted exact value is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_tick_time(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir)
{
return snd_pcm_hw_param_set(pcm, params, SND_TRY, SND_PCM_HW_PARAM_TICK_TIME, val, dir);
}
/**
* \brief Restrict a configuration space with a minimum tick time
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate minimum tick duration in us (on return filled with actual minimum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact minimum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_tick_time_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
{
return snd_pcm_hw_param_set_min(pcm, params, SND_TRY, SND_PCM_HW_PARAM_TICK_TIME, val, dir);
}
/**
* \brief Restrict a configuration space with a maximum tick time
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate maximum tick duration in us (on return filled with actual maximum)
* \param dir Sub unit direction (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact maximum is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_tick_time_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
{
return snd_pcm_hw_param_set_max(pcm, params, SND_TRY, SND_PCM_HW_PARAM_TICK_TIME, val, dir);
}
/**
* \brief Restrict a configuration space to have tick times in a given range
* \param pcm PCM handle
* \param params Configuration space
* \param min approximate minimum tick duration in us (on return filled with actual minimum)
* \param mindir Sub unit direction for minimum (on return filled with actual direction)
* \param max approximate maximum tick duration in us (on return filled with actual maximum)
* \param maxdir Sub unit direction for maximum (on return filled with actual direction)
* \return 0 otherwise a negative error code if configuration space would become empty
*
* Wanted/actual exact min/max is <,=,> val following dir (-1,0,1)
*/
int snd_pcm_hw_params_set_tick_time_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, int *mindir, unsigned int *max, int *maxdir)
{
return snd_pcm_hw_param_set_minmax(pcm, params, SND_TRY, SND_PCM_HW_PARAM_TICK_TIME, min, mindir, max, maxdir);
}
/**
* \brief Restrict a configuration space to have tick time nearest to a target
* \param pcm PCM handle
* \param params Configuration space
* \param val approximate target tick duration in us
* \return approximate choosen tick duration in us
*
* target/choosen exact value is <,=,> val following dir (-1,0,1)
*/
unsigned int snd_pcm_hw_params_set_tick_time_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int *dir)
{
return snd_pcm_hw_param_set_near(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, val, dir);
}
/**
* \brief Restrict a configuration space to contain only its minimum tick time
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate tick duration in us
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
unsigned int snd_pcm_hw_params_set_tick_time_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, dir);
}
/**
* \brief Restrict a configuration space to contain only its maximum tick time
* \param pcm PCM handle
* \param params Configuration space
* \param dir Sub unit direction
* \return approximate tick duration in us
*
* Actual exact value is <,=,> the approximate one following dir (-1, 0, 1)
*/
unsigned int snd_pcm_hw_params_set_tick_time_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir)
{
return snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, dir);
}
/**
* \brief Return current software configuration for a PCM
* \param pcm PCM handle
* \param params Software configuration container
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
{
assert(pcm && params);
assert(pcm->setup);
params->tstamp_mode = pcm->tstamp_mode;
params->period_step = pcm->period_step;
params->sleep_min = pcm->sleep_min;
params->avail_min = pcm->avail_min;
params->xfer_align = pcm->xfer_align;
params->start_threshold = pcm->start_threshold;
params->stop_threshold = pcm->stop_threshold;
params->silence_threshold = pcm->silence_threshold;
params->silence_size = pcm->silence_size;
params->boundary = pcm->boundary;
return 0;
}
/**
* \brief Dump a software configuration
* \param params Software configuration container
* \param out Output handle
* \return 0 on success otherwise a negative error code
*/
int snd_pcm_sw_params_dump(snd_pcm_sw_params_t *params, snd_output_t *out)
{
snd_output_printf(out, "start_mode: %s\n", snd_pcm_start_mode_name(snd_pcm_sw_params_get_start_mode(params)));
snd_output_printf(out, "xrun_mode: %s\n", snd_pcm_xrun_mode_name(snd_pcm_sw_params_get_xrun_mode(params)));
snd_output_printf(out, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(snd_pcm_sw_params_get_tstamp_mode(params)));
snd_output_printf(out, "period_step: %u\n", params->period_step);
snd_output_printf(out, "sleep_min: %u\n", params->sleep_min);
snd_output_printf(out, "avail_min: %lu\n", params->avail_min);
snd_output_printf(out, "xfer_align: %lu\n", params->xfer_align);
snd_output_printf(out, "silence_threshold: %lu\n", params->silence_threshold);
snd_output_printf(out, "silence_size: %lu\n", params->silence_size);
snd_output_printf(out, "boundary: %lu\n", params->boundary);
return 0;
}
/**
* \brief get size of #snd_pcm_sw_params_t
* \return size in bytes
*/
size_t snd_pcm_sw_params_sizeof()
{
return sizeof(snd_pcm_sw_params_t);
}
/**
* \brief allocate an invalid #snd_pcm_sw_params_t using standard malloc
* \param ptr returned pointer
* \return 0 on success otherwise negative error code
*/
int snd_pcm_sw_params_malloc(snd_pcm_sw_params_t **ptr)
{
assert(ptr);
*ptr = calloc(1, sizeof(snd_pcm_sw_params_t));
if (!*ptr)
return -ENOMEM;
return 0;
}
/**
* \brief frees a previously allocated #snd_pcm_sw_params_t
* \param pointer to object to free
*/
void snd_pcm_sw_params_free(snd_pcm_sw_params_t *obj)
{
free(obj);
}
/**
* \brief copy one #snd_pcm_sw_params_t to another
* \param dst pointer to destination
* \param src pointer to source
*/
void snd_pcm_sw_params_copy(snd_pcm_sw_params_t *dst, const snd_pcm_sw_params_t *src)
{
assert(dst && src);
*dst = *src;
}
/**
* \brief (DEPRECATED) Set start mode inside a software configuration container
* \param pcm PCM handle
* \param params Software configuration container
* \param val Start mode
* \return 0 otherwise a negative error code
*/
int snd_pcm_sw_params_set_start_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_start_t val)
{
assert(pcm && params);
switch (val) {
case SND_PCM_START_DATA:
params->start_threshold = 1;
break;
case SND_PCM_START_EXPLICIT:
params->start_threshold = pcm->boundary;
break;
default:
assert(0);
break;
}
return 0;
}
#ifndef DOC_HIDDEN
link_warning(snd_pcm_sw_params_set_start_mode, "Warning: start_mode is deprecated, consider to use start_threshold");
#endif
/**
* \brief (DEPRECATED) Get start mode from a software configuration container
* \param params Software configuration container
* \return start mode
*/
snd_pcm_start_t snd_pcm_sw_params_get_start_mode(const snd_pcm_sw_params_t *params)
{
assert(params);
/* FIXME: Ugly */
return params->start_threshold > 1024 * 1024 ? SND_PCM_START_EXPLICIT : SND_PCM_START_DATA;
}
#ifndef DOC_HIDDEN
link_warning(snd_pcm_sw_params_get_start_mode, "Warning: start_mode is deprecated, consider to use start_threshold");
#endif
/**
* \brief (DEPRECATED) Set xrun mode inside a software configuration container
* \param pcm PCM handle
* \param params Software configuration container
* \param val Xrun mode
* \return 0 otherwise a negative error code
*/
int snd_pcm_sw_params_set_xrun_mode(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_xrun_t val)
{
assert(pcm && params);
switch (val) {
case SND_PCM_XRUN_STOP:
params->stop_threshold = pcm->buffer_size;
break;
case SND_PCM_XRUN_NONE:
params->stop_threshold = pcm->boundary;
break;
default:
assert(0);
break;
}
return 0;
}
#ifndef DOC_HIDDEN
link_warning(snd_pcm_sw_params_set_xrun_mode, "Warning: xrun_mode is deprecated, consider to use stop_threshold");
#endif
/**
* \brief (DEPRECATED) Get xrun mode from a software configuration container
* \param params Software configuration container
* \return xrun mode
*/
snd_pcm_xrun_t snd_pcm_sw_params_get_xrun_mode(const snd_pcm_sw_params_t *params)
{
assert(params);
/* FIXME: Ugly */
return params->stop_threshold > 1024 * 1024 ? SND_PCM_XRUN_NONE : SND_PCM_XRUN_STOP;
}
#ifndef DOC_HIDDEN
link_warning(snd_pcm_sw_params_get_xrun_mode, "Warning: xrun_mode is deprecated, consider to use stop_threshold");
#endif
/**
* \brief Set timestamp mode inside a software configuration container
* \param pcm PCM handle
* \param params Software configuration container
* \param val Timestamp mode
* \return 0 otherwise a negative error code
*/
int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_tstamp_t val)
{
assert(pcm && params);
assert(val <= SND_PCM_TSTAMP_LAST);
params->tstamp_mode = val;
return 0;
}
/**
* \brief Get timestamp mode from a software configuration container
* \param params Software configuration container
* \return timestamp mode
*/
snd_pcm_tstamp_t snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params)
{
assert(params);
return params->tstamp_mode;
}
#if 0
int snd_pcm_sw_params_set_period_step(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, unsigned int val)
{
assert(pcm && params);
params->period_step = val;
return 0;
}
unsigned int snd_pcm_sw_params_get_period_step(const snd_pcm_sw_params_t *params)
{
assert(params);
return params->period_step;
}
#endif
/**
* \brief Set minimum number of ticks to sleep inside a software configuration container
* \param pcm PCM handle
* \param params Software configuration container
* \param val Minimum ticks to sleep or 0 to disable the use of tick timer
* \return 0 otherwise a negative error code
*/
int snd_pcm_sw_params_set_sleep_min(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, unsigned int val)
{
assert(pcm && params);
params->sleep_min = val;
return 0;
}
/**
* \brief Get minimum numbers of ticks to sleep from a software configuration container
* \param params Software configuration container
* \return minimum number of ticks to sleep or 0 if tick timer is disabled
*/
unsigned int snd_pcm_sw_params_get_sleep_min(const snd_pcm_sw_params_t *params)
{
assert(params);
return params->sleep_min;
}
/**
* \brief Set avail min inside a software configuration container
* \param pcm PCM handle
* \param params Software configuration container
* \param val Minimum avail frames to consider PCM ready
* \return 0 otherwise a negative error code
*/
int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
{
assert(pcm && params);
params->avail_min = val;
return 0;
}
/**
* \brief Get avail min from a software configuration container
* \param params Software configuration container
* \return minimum available frames to consider PCM ready
*/
snd_pcm_uframes_t snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params)
{
assert(params);
return params->avail_min;
}
/**
* \brief Set xfer align inside a software configuration container
* \param pcm PCM handle
* \param params Software configuration container
* \param val Chunk size (frames are attempted to be transferred in chunks)
* \return 0 otherwise a negative error code
*/
int snd_pcm_sw_params_set_xfer_align(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
{
assert(pcm && params);
assert(val % pcm->min_align == 0);
params->xfer_align = val;
return 0;
}
/**
* \brief Get xfer align from a software configuration container
* \param params Software configuration container
* \return Chunk size (frames are attempted to be transferred in chunks)
*/
snd_pcm_uframes_t snd_pcm_sw_params_get_xfer_align(const snd_pcm_sw_params_t *params)
{
assert(params);
return params->xfer_align;
}
/**
* \brief Set start threshold inside a software configuration container
* \param pcm PCM handle
* \param params Software configuration container
* \param val Start threshold in frames
* \return 0 otherwise a negative error code
*
* PCM is automatically started when playback frames available to PCM
* are >= threshold or when requested capture frames are >= threshold
*/
int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
{
assert(pcm && params);
params->start_threshold = val;
return 0;
}
/**
* \brief Get start threshold from a software configuration container
* \param params Software configuration container
* \return Start threshold in frames
*
* PCM is automatically started when playback frames available to PCM
* are >= threshold or when requested capture frames are >= threshold
*/
snd_pcm_uframes_t snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *params)
{
assert(params);
return params->start_threshold;
}
/**
* \brief Set stop threshold inside a software configuration container
* \param pcm PCM handle
* \param params Software configuration container
* \param val Stop threshold in frames
* \return 0 otherwise a negative error code
*
* PCM is automatically stopped in #SND_PCM_STATE_XRUN state when available
* frames is >= threshold
*/
int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
{
assert(pcm && params);
params->stop_threshold = val;
return 0;
}
/**
* \brief Get stop threshold from a software configuration container
* \param params Software configuration container
* \return Stop threshold in frames
*
* PCM is automatically stopped in #SND_PCM_STATE_XRUN state when available
* frames is >= threshold
*/
snd_pcm_uframes_t snd_pcm_sw_params_get_stop_threshold(const snd_pcm_sw_params_t *params)
{
assert(params);
return params->stop_threshold;
}
/**
* \brief Set silence threshold inside a software configuration container
* \param pcm PCM handle
* \param params Software configuration container
* \param val Silence threshold in frames
* \return 0 otherwise a negative error code
*
* A portion of playback buffer is overwritten with silence (see
* #snd_pcm_sw_params_set_silence_size) when playback underrun is nearer
* than silence threshold
*/
int snd_pcm_sw_params_set_silence_threshold(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
{
assert(pcm && params);
assert(val + params->silence_size <= pcm->buffer_size);
params->silence_threshold = val;
return 0;
}
/**
* \brief Get silence threshold from a software configuration container
* \param params Software configuration container
* \return Silence threshold in frames
*
* A portion of playback buffer is overwritten with silence (see
* #snd_pcm_sw_params_get_silence_size) when playback underrun is nearer
* than silence threshold
*/
snd_pcm_uframes_t snd_pcm_sw_params_get_silence_threshold(const snd_pcm_sw_params_t *params)
{
assert(params);
return params->silence_threshold;
}
/**
* \brief Set silence size inside a software configuration container
* \param pcm PCM handle
* \param params Software configuration container
* \param val Silence size in frames (0 for disabled)
* \return 0 otherwise a negative error code
*
* A portion of playback buffer is overwritten with silence when playback
* underrun is nearer than silence threshold (see
* #snd_pcm_sw_params_set_silence_threshold)
*/
int snd_pcm_sw_params_set_silence_size(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)
{
assert(pcm && params);
assert(val + params->silence_threshold <= pcm->buffer_size);
params->silence_size = val;
return 0;
}
/**
* \brief Get silence size from a software configuration container
* \param params Software configuration container
* \return Silence size in frames (0 for disabled)
*
* A portion of playback buffer is overwritten with silence when playback
* underrun is nearer than silence threshold (see
* #snd_pcm_sw_params_set_silence_threshold)
*/
snd_pcm_uframes_t snd_pcm_sw_params_get_silence_size(const snd_pcm_sw_params_t *params)
{
assert(params);
return params->silence_size;
}
/**
* \brief get size of #snd_pcm_status_t
* \return size in bytes
*/
size_t snd_pcm_status_sizeof()
{
return sizeof(snd_pcm_status_t);
}
/**
* \brief allocate an invalid #snd_pcm_status_t using standard malloc
* \param ptr returned pointer
* \return 0 on success otherwise negative error code
*/
int snd_pcm_status_malloc(snd_pcm_status_t **ptr)
{
assert(ptr);
*ptr = calloc(1, sizeof(snd_pcm_status_t));
if (!*ptr)
return -ENOMEM;
return 0;
}
/**
* \brief frees a previously allocated #snd_pcm_status_t
* \param pointer to object to free
*/
void snd_pcm_status_free(snd_pcm_status_t *obj)
{
free(obj);
}
/**
* \brief copy one #snd_pcm_status_t to another
* \param dst pointer to destination
* \param src pointer to source
*/
void snd_pcm_status_copy(snd_pcm_status_t *dst, const snd_pcm_status_t *src)
{
assert(dst && src);
*dst = *src;
}
/**
* \brief Get state from a PCM status container (see #snd_pcm_state)
* \return PCM state
*/
snd_pcm_state_t snd_pcm_status_get_state(const snd_pcm_status_t *obj)
{
assert(obj);
return obj->state;
}
/**
* \brief Get trigger timestamp from a PCM status container
* \param ptr Pointer to returned timestamp
*/
void snd_pcm_status_get_trigger_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t *ptr)
{
assert(obj && ptr);
*ptr = obj->trigger_tstamp;
}
/**
* \brief Get "now" timestamp from a PCM status container
* \param ptr Pointer to returned timestamp
*/
void snd_pcm_status_get_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t *ptr)
{
assert(obj && ptr);
*ptr = obj->tstamp;
}
/**
* \brief Get delay from a PCM status container (see #snd_pcm_delay)
* \return Delay in frames
*
* Delay is distance between current application frame position and
* sound frame position.
* It's positive and less than buffer size in normal situation,
* negative on playback underrun and greater than buffer size on
* capture overrun.
*/
snd_pcm_sframes_t snd_pcm_status_get_delay(const snd_pcm_status_t *obj)
{
assert(obj);
return obj->delay;
}
/**
* \brief Get number of frames available from a PCM status container (see #snd_pcm_avail_update)
* \return Number of frames ready to be read/written
*/
snd_pcm_uframes_t snd_pcm_status_get_avail(const snd_pcm_status_t *obj)
{
assert(obj);
return obj->avail;
}
/**
* \brief Get maximum number of frames available from a PCM status container after last #snd_pcm_status call
* \return Maximum number of frames ready to be read/written
*/
snd_pcm_uframes_t snd_pcm_status_get_avail_max(const snd_pcm_status_t *obj)
{
assert(obj);
return obj->avail_max;
}
/**
* \brief Get count of ADC overrange detections since last call
* \return Count of ADC overrange detections
*/
snd_pcm_uframes_t snd_pcm_status_get_overrange(const snd_pcm_status_t *obj)
{
assert(obj);
return obj->overrange;
}
/**
* \brief get size of #snd_pcm_info_t
* \return size in bytes
*/
size_t snd_pcm_info_sizeof()
{
return sizeof(snd_pcm_info_t);
}
/**
* \brief allocate an invalid #snd_pcm_info_t using standard malloc
* \param ptr returned pointer
* \return 0 on success otherwise negative error code
*/
int snd_pcm_info_malloc(snd_pcm_info_t **ptr)
{
assert(ptr);
*ptr = calloc(1, sizeof(snd_pcm_info_t));
if (!*ptr)
return -ENOMEM;
return 0;
}
/**
* \brief frees a previously allocated #snd_pcm_info_t
* \param pointer to object to free
*/
void snd_pcm_info_free(snd_pcm_info_t *obj)
{
free(obj);
}
/**
* \brief copy one #snd_pcm_info_t to another
* \param dst pointer to destination
* \param src pointer to source
*/
void snd_pcm_info_copy(snd_pcm_info_t *dst, const snd_pcm_info_t *src)
{
assert(dst && src);
*dst = *src;
}
/**
* \brief Get device from a PCM info container
* \param obj PCM info container
* \return device number
*/
unsigned int snd_pcm_info_get_device(const snd_pcm_info_t *obj)
{
assert(obj);
return obj->device;
}
/**
* \brief Get subdevice from a PCM info container
* \param obj PCM info container
* \return subdevice number
*/
unsigned int snd_pcm_info_get_subdevice(const snd_pcm_info_t *obj)
{
assert(obj);
return obj->subdevice;
}
/**
* \brief Get stream (direction) from a PCM info container
* \param obj PCM info container
* \return stream
*/
snd_pcm_stream_t snd_pcm_info_get_stream(const snd_pcm_info_t *obj)
{
assert(obj);
return obj->stream;
}
/**
* \brief Get card from a PCM info container
* \param obj PCM info container
* \return card number otherwise a negative error code if not associable to a card
*/
int snd_pcm_info_get_card(const snd_pcm_info_t *obj)
{
assert(obj);
return obj->card;
}
/**
* \brief Get id from a PCM info container
* \param obj PCM info container
* \return short id of PCM
*/
const char *snd_pcm_info_get_id(const snd_pcm_info_t *obj)
{
assert(obj);
return obj->id;
}
/**
* \brief Get name from a PCM info container
* \param obj PCM info container
* \return name of PCM
*/
const char *snd_pcm_info_get_name(const snd_pcm_info_t *obj)
{
assert(obj);
return obj->name;
}
/**
* \brief Get subdevice name from a PCM info container
* \param obj PCM info container
* \return name of used PCM subdevice
*/
const char *snd_pcm_info_get_subdevice_name(const snd_pcm_info_t *obj)
{
assert(obj);
return obj->subname;
}
/**
* \brief Get class from a PCM info container
* \param obj PCM info container
* \return class of PCM
*/
snd_pcm_class_t snd_pcm_info_get_class(const snd_pcm_info_t *obj)
{
assert(obj);
return obj->dev_class;
}
/**
* \brief Get subclass from a PCM info container
* \param obj PCM info container
* \return subclass of PCM
*/
snd_pcm_subclass_t snd_pcm_info_get_subclass(const snd_pcm_info_t *obj)
{
assert(obj);
return obj->dev_subclass;
}
/**
* \brief Get subdevices count from a PCM info container
* \param obj PCM info container
* \return subdevices total count of PCM
*/
unsigned int snd_pcm_info_get_subdevices_count(const snd_pcm_info_t *obj)
{
assert(obj);
return obj->subdevices_count;
}
/**
* \brief Get available subdevices count from a PCM info container
* \param obj PCM info container
* \return available subdevices count of PCM
*/
unsigned int snd_pcm_info_get_subdevices_avail(const snd_pcm_info_t *obj)
{
assert(obj);
return obj->subdevices_avail;
}
/**
* \brief Get hardware synchronization ID from a PCM info container
* \param obj PCM info container
* \return hardware synchronization ID
*/
snd_pcm_sync_id_t snd_pcm_info_get_sync(const snd_pcm_info_t *obj)
{
snd_pcm_sync_id_t res;
assert(obj);
memcpy(&res, &obj->sync, sizeof(res));
return res;
}
/**
* \brief Set wanted device inside a PCM info container (see #snd_ctl_pcm_info)
* \param obj PCM info container
* \param val Device number
*/
void snd_pcm_info_set_device(snd_pcm_info_t *obj, unsigned int val)
{
assert(obj);
obj->device = val;
}
/**
* \brief Set wanted subdevice inside a PCM info container (see #snd_ctl_pcm_info)
* \param obj PCM info container
* \param val Subdevice number
*/
void snd_pcm_info_set_subdevice(snd_pcm_info_t *obj, unsigned int val)
{
assert(obj);
obj->subdevice = val;
}
/**
* \brief Set wanted stream inside a PCM info container (see #snd_ctl_pcm_info)
* \param obj PCM info container
* \param val Stream
*/
void snd_pcm_info_set_stream(snd_pcm_info_t *obj, snd_pcm_stream_t val)
{
assert(obj);
obj->stream = val;
}
/**
* \brief Application request to access a portion of direct (mmap) area
* \param pcm PCM handle
* \param areas Returned mmap channel areas
* \param offset Returned mmap area offset in area steps (== frames)
* \param size mmap area portion size in frames (wanted on entry, contiguous available on exit)
* \return 0 on success otherwise a negative error code
*
* The function should be called before a sample-direct area can be accessed.
* The resulting size parameter is always less or equal to the input count of frames
* and can be zero, if no frames can be processed (the ring buffer is full).
*
* See the snd_pcm_mmap_commit() function to finish the frame processing in
* the direct areas.
*
*/
int snd_pcm_mmap_begin(snd_pcm_t *pcm,
const snd_pcm_channel_area_t **areas,
snd_pcm_uframes_t *offset,
snd_pcm_uframes_t *frames)
{
snd_pcm_uframes_t cont;
snd_pcm_uframes_t avail;
snd_pcm_uframes_t f;
assert(pcm && areas && offset && frames);
if (pcm->stopped_areas &&
snd_pcm_state(pcm) != SND_PCM_STATE_RUNNING)
*areas = pcm->stopped_areas;
else
*areas = pcm->running_areas;
*offset = *pcm->appl_ptr % pcm->buffer_size;
cont = pcm->buffer_size - *offset;
avail = snd_pcm_mmap_avail(pcm);
f = *frames;
if (f > avail)
f = avail;
if (f > cont)
f = cont;
*frames = f;
return 0;
}
/**
* \brief Application has completed the access to area requested with #snd_pcm_mmap_begin
* \param pcm PCM handle
* \param offset area offset in area steps (== frames)
* \param size area portion size in frames
* \return 0 on success otherwise a negative error code
*
* To call this with offset/frames values different from that returned
* by snd_pcm_mmap_begin() has undefined effects and it has to be avoided.
*
* Example:
\code
double phase = 0;
const snd_pcm_area_t *areas;
snd_pcm_uframes_t offset, frames;
frames = frame_buffer_size;
err = snd_pcm_mmap_begin(pcm_handle, &areas, &offset, &frames);
if (err < 0)
error(err);
// this function fills the areas from offset with count of frames
generate_sine(areas, offset, frames, &phase);
err = snd_pcm_mmap_commit(pcm_handle, offset, frames);
if (err < 0)
error(err);
\endcode
*
* Look to the \ref example_test_pcm "Sine-wave generator" example
* for more details about the generate_sine function.
*/
int snd_pcm_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset,
snd_pcm_uframes_t frames)
{
assert(pcm);
assert(offset == *pcm->appl_ptr % pcm->buffer_size);
assert(frames <= snd_pcm_mmap_avail(pcm));
return pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames);
}
#ifndef DOC_HIDDEN
int _snd_pcm_poll_descriptor(snd_pcm_t *pcm)
{
assert(pcm);
return pcm->poll_fd;
}
void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
void *buf)
{
unsigned int channel;
unsigned int channels = pcm->channels;
for (channel = 0; channel < channels; ++channel, ++areas) {
areas->addr = buf;
areas->first = channel * pcm->sample_bits;
areas->step = pcm->frame_bits;
}
}
void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
void **bufs)
{
unsigned int channel;
unsigned int channels = pcm->channels;
for (channel = 0; channel < channels; ++channel, ++areas, ++bufs) {
areas->addr = *bufs;
areas->first = 0;
areas->step = pcm->sample_bits;
}
}
snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas,
snd_pcm_uframes_t offset, snd_pcm_uframes_t size,
snd_pcm_xfer_areas_func_t func)
{
snd_pcm_uframes_t xfer = 0;
int err = 0;
snd_pcm_state_t state = snd_pcm_state(pcm);
if (size == 0)
return 0;
if (size > pcm->xfer_align)
size -= size % pcm->xfer_align;
switch (state) {
case SND_PCM_STATE_PREPARED:
if (size >= pcm->start_threshold) {
err = snd_pcm_start(pcm);
if (err < 0)
goto _end;
}
break;
case SND_PCM_STATE_DRAINING:
case SND_PCM_STATE_RUNNING:
break;
case SND_PCM_STATE_XRUN:
return -EPIPE;
default:
return -EBADFD;
}
while (size > 0) {
snd_pcm_uframes_t frames;
snd_pcm_sframes_t avail;
_again:
avail = snd_pcm_avail_update(pcm);
if (avail < 0) {
err = -EPIPE;
goto _end;
}
if (state == SND_PCM_STATE_DRAINING) {
if (avail == 0) {
err = -EPIPE;
goto _end;
}
} else if (avail == 0 ||
(size >= pcm->xfer_align &&
(snd_pcm_uframes_t) avail < pcm->xfer_align)) {
if (pcm->mode & SND_PCM_NONBLOCK) {
err = -EAGAIN;
goto _end;
}
err = snd_pcm_wait(pcm, -1);
if (err < 0)
break;
state = snd_pcm_state(pcm);
goto _again;
}
if ((snd_pcm_uframes_t) avail > pcm->xfer_align)
avail -= avail % pcm->xfer_align;
frames = size;
if (frames > (snd_pcm_uframes_t) avail)
frames = avail;
assert(frames != 0);
err = func(pcm, areas, offset, frames);
if (err < 0)
break;
assert((snd_pcm_uframes_t)err == frames);
offset += frames;
size -= frames;
xfer += frames;
#if 0
state = snd_pcm_state(pcm);
if (state == SND_PCM_STATE_XRUN) {
err = -EPIPE;
goto _end;
}
#endif
}
_end:
return xfer > 0 ? (snd_pcm_sframes_t) xfer : err;
}
snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas,
snd_pcm_uframes_t offset, snd_pcm_uframes_t size,
snd_pcm_xfer_areas_func_t func)
{
snd_pcm_uframes_t xfer = 0;
int err = 0;
snd_pcm_state_t state = snd_pcm_state(pcm);
if (size == 0)
return 0;
if (size > pcm->xfer_align)
size -= size % pcm->xfer_align;
switch (state) {
case SND_PCM_STATE_PREPARED:
case SND_PCM_STATE_RUNNING:
break;
case SND_PCM_STATE_XRUN:
return -EPIPE;
default:
return -EBADFD;
}
while (size > 0) {
snd_pcm_uframes_t frames;
snd_pcm_sframes_t avail;
_again:
avail = snd_pcm_avail_update(pcm);
if (avail < 0) {
err = -EPIPE;
goto _end;
}
if (state == SND_PCM_STATE_PREPARED) {
if (avail == 0) {
err = -EPIPE;
goto _end;
}
} else if (avail == 0 ||
(size >= pcm->xfer_align &&
(snd_pcm_uframes_t) avail < pcm->xfer_align)) {
if (pcm->mode & SND_PCM_NONBLOCK) {
err = -EAGAIN;
goto _end;
}
err = snd_pcm_wait(pcm, -1);
if (err < 0)
break;
state = snd_pcm_state(pcm);
goto _again;
}
if ((snd_pcm_uframes_t) avail > pcm->xfer_align)
avail -= avail % pcm->xfer_align;
frames = size;
if (frames > (snd_pcm_uframes_t) avail)
frames = avail;
assert(frames != 0);
err = func(pcm, areas, offset, frames);
if (err < 0)
break;
assert((snd_pcm_uframes_t)err == frames);
offset += frames;
size -= frames;
xfer += frames;
#if 0
state = snd_pcm_state(pcm);
if (state == SND_PCM_STATE_XRUN) {
err = -EPIPE;
goto _end;
}
#endif
if (state == SND_PCM_STATE_PREPARED) {
snd_pcm_sframes_t hw_avail = pcm->buffer_size - avail;
hw_avail += frames;
if (hw_avail >= (snd_pcm_sframes_t) pcm->start_threshold) {
err = snd_pcm_start(pcm);
if (err < 0)
goto _end;
}
}
}
_end:
return xfer > 0 ? (snd_pcm_sframes_t) xfer : err;
}
snd_pcm_uframes_t _snd_pcm_mmap_hw_ptr(snd_pcm_t *pcm)
{
return *pcm->hw_ptr;
}
snd_pcm_uframes_t _snd_pcm_boundary(snd_pcm_t *pcm)
{
return pcm->boundary;
}
static const char *names[SND_PCM_HW_PARAM_LAST + 1] = {
[SND_PCM_HW_PARAM_FORMAT] = "format",
[SND_PCM_HW_PARAM_CHANNELS] = "channels",
[SND_PCM_HW_PARAM_RATE] = "rate",
[SND_PCM_HW_PARAM_PERIOD_TIME] = "period_time",
[SND_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time"
};
int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf,
snd_config_t **_pcm_conf, unsigned int count, ...)
{
snd_config_iterator_t i, next;
const char *str;
struct {
unsigned int index;
int flags;
void *ptr;
int present;
} fields[count];
unsigned int k;
snd_config_t *pcm_conf = NULL;
int err;
int to_free = 0;
va_list args;
assert(root);
assert(conf);
assert(_pcm_conf);
if (snd_config_get_string(conf, &str) >= 0) {
err = snd_config_search_definition(root, "pcm_slave", str, &conf);
if (err < 0) {
SNDERR("Invalid slave definition");
return -EINVAL;
}
to_free = 1;
}
if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) {
SNDERR("Invalid slave definition");
err = -EINVAL;
goto _err;
}
va_start(args, count);
for (k = 0; k < count; ++k) {
fields[k].index = va_arg(args, int);
fields[k].flags = va_arg(args, int);
fields[k].ptr = va_arg(args, void *);
fields[k].present = 0;
}
va_end(args);
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
const char *id;
if (snd_config_get_id(n, &id) < 0)
continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "pcm") == 0) {
if (pcm_conf != NULL)
snd_config_delete(pcm_conf);
if ((err = snd_config_copy(&pcm_conf, n)) < 0)
goto _err;
continue;
}
for (k = 0; k < count; ++k) {
unsigned int idx = fields[k].index;
long v;
assert(idx < SND_PCM_HW_PARAM_LAST);
assert(names[idx]);
if (strcmp(id, names[idx]) != 0)
continue;
switch (idx) {
case SND_PCM_HW_PARAM_FORMAT:
{
snd_pcm_format_t f;
err = snd_config_get_string(n, &str);
if (err < 0) {
_invalid:
SNDERR("invalid type for %s", id);
goto _err;
}
if ((fields[k].flags & SCONF_UNCHANGED) &&
strcasecmp(str, "unchanged") == 0) {
*(snd_pcm_format_t*)fields[k].ptr = (snd_pcm_format_t) -2;
break;
}
f = snd_pcm_format_value(str);
if (f == SND_PCM_FORMAT_UNKNOWN) {
SNDERR("unknown format");
err = -EINVAL;
goto _err;
}
*(snd_pcm_format_t*)fields[k].ptr = f;
break;
}
default:
if ((fields[k].flags & SCONF_UNCHANGED)) {
err = snd_config_get_string(n, &str);
if (err >= 0 &&
strcasecmp(str, "unchanged") == 0) {
*(int*)fields[k].ptr = -2;
break;
}
}
err = snd_config_get_integer(n, &v);
if (err < 0)
goto _invalid;
*(int*)fields[k].ptr = v;
break;
}
fields[k].present = 1;
break;
}
if (k < count)
continue;
SNDERR("Unknown field %s", id);
err = -EINVAL;
goto _err;
}
if (!pcm_conf) {
SNDERR("missing field pcm");
err = -EINVAL;
goto _err;
}
for (k = 0; k < count; ++k) {
if ((fields[k].flags & SCONF_MANDATORY) && !fields[k].present) {
SNDERR("missing field %s", names[fields[k].index]);
err = -EINVAL;
goto _err;
}
}
*_pcm_conf = pcm_conf;
pcm_conf = NULL;
err = 0;
_err:
if (pcm_conf)
snd_config_delete(pcm_conf);
if (to_free)
snd_config_delete(conf);
return err;
}
int snd_pcm_conf_generic_id(const char *id)
{
static const char *ids[] = { "comment", "type" };
unsigned int k;
for (k = 0; k < sizeof(ids) / sizeof(ids[0]); ++k) {
if (strcmp(id, ids[k]) == 0)
return 1;
}
return 0;
}
#endif