- 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
}
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "host") == 0) {
+++ /dev/null
-/*! \page conf Configuration files
-
-<P>Configuration files are using a simple format allowing the modern
-data description like nesting and array assignments.</P>
-
-\section conf_whitespace Whitespace
-
-Whitespace is the collective name given to spaces (blanks), horizontal and
-vertical tabs, newline characters, and comments. Whitespace can serve to
-indicate where configuration tokens start and end, but beyond this function,
-any surplus whitespace is discarded. For example, the two sequences
-
-\code
- a 1 b 2
-\endcode
-
-and
-
-\code
- a 1
- b 2
-\endcode
-
-are lexically equivalent and parse identically to give the four tokens:
-
-\code
-a
-1
-b
-2
-\endcode
-
-The ASCII characters representing whitespace can occur within literal
-strings, int which case they are protected from the normal parsing process
-(tey remain as part of the string). For example:
-
-\code
- name "John Smith"
-\endcode
-
-parses to two tokens, including the single literal-string token "John
-Smith".
-
-\section conf_linesplicing Line splicing with \
-
-A special case occurs, if the final newline character encountered is
-preceded by a backslash (\) in the string value definition. The backslash
-and new line are both discarded, allowing two physical lines of text to be
-treated as one unit.
-
-\code
-"John \
-Smith"
-\endcode
-
-is parsed as "John Smith".
-
-\section conf_comments Comments
-
-A single-line comments are defined using character #. The comment can start
-in any position, and extends until the next new line.
-
-\code
- a 1 # this is a comment
-\endcode
-
-\section conf_include Include another configuration file
-
-A new configuration file can be included using <filename> syntax. The global
-configuration directory can be referenced using <confdir:filename> syntax.
-
-\code
-</etc/alsa1.conf>
-<confdir:pcm/surround.conf>
-\endcode
-
-\section conf_punctuators Punctuators
-
-The configuration punctuators (also known as separators) are:
-
-\code
- {} [] , ; = . ' " new-line form-feed carriage-return whitespace
-\endcode
-
-\subsection conf_braces Braces
-
-Open and close braces { } indicate the start and end of a compound
-statement:
-
-\code
-a {
- b 1
-}
-\endcode
-
-\subsection conf_brackets Brackets
-
-Open and close brackets indicate single array definition. The identificators
-are automatically generated starting with zero.
-
-\code
-a [
- "first"
- "second"
-]
-\endcode
-
-Above code is equal to
-
-\code
-a.0 "first"
-a.1 "second"
-\endcode
-
-\subsection conf_comma_semicolon Comma and semicolon
-
-The comma (,) or semicolon (;) can separate the value assignments. It is not
-strictly required to use these separators, because any whitespace supplies
-them.
-
-\code
-a 1;
-b 1,
-\endcode
-
-\subsection conf_equal Equal sign
-
-The equal sign (=) separates can separate variable declarations from
-initialization lists:
-
-\code
-a=1
-b=2
-\endcode
-
-Using the equal signs is not required, because any whitespace supplies
-them.
-
-\section conf_assigns Assigns
-
-The configuration file defines id (key) and value pairs. The id (key) can be
-composed from any ASCII digits or chars from a to z or A to Z, including
-char _. The value can be either a string, integer or real number.
-
-\subsection conf_single Single assign
-
-\code
-a 1 # is equal to
-a=1 # is equal to
-a=1; # is equal to
-a 1,
-\endcode
-
-\subsection conf_compound Compound assign (definition using braces)
-
-\code
-a {
- b = 1
-}
-a={
- b 1,
-}
-\endcode
-
-\section conf_compound1 Compound assign (one key definition)
-
-\code
-a.b 1
-a.b=1
-\endcode
-
-\subsection conf_array Array assign (definition using brackets)
-
-\code
-a [
- "first"
- "second"
-]
-\endcode
-
-\subsection conf_array1 Array assign (one key definition)
-
-\code
-a.0 "first"
-a.1 "second"
-\endcode
-
-\section conf_summary Summary
-
-\code
-# Configuration file syntax
-
-# Include a new configuration file
-<filename>
-
-# Simple assign
-name [=] value [,|;]
-
-# Compound assign (first style)
-name [=] {
- name1 [=] value [,|;]
- ...
-}
-
-# Compound assign (second style)
-name.name1 [=] value [,|;]
-
-# Array assign (first style)
-name [
- value0 [,|;]
- value1 [,|;]
- ...
-]
-
-# Array assign (second style)
-name.0 [=] value0 [,|;]
-name.1 [=] value1 [,|;]
-\endcode
-
-*/
+++ /dev/null
-/*! \page confarg Configuration - runtime arguments
-
-<P>The ALSA library can accept runtime arguments for some configuration
-blocks. This extension is on top of the basic syntax of the configuration
-files.<P>
-
-\section confarg_define Defining arguments
-
-Arguments are specified by id (key) @args and array values containing
-the string names of arguments:
-
-\code
-@args [ CARD ] # or
-@args.0 CARD
-\endcode
-
-\section confarg_type Defining argument type and default value
-
-Arguments type is specified by id (key) @args and argument name. The type
-and default value is specified in the compound:
-
-\code
-@args.CARD {
- type string
- default "abcd"
-}
-\endcode
-
-\section confarg_refer Refering argument
-
-Arguments are refered by dollar-sign ($) and name of argument:
-
-\code
- card $CARD
-\endcode
-
-\section confarg_example Example
-
-\code
-pcm.demo {
- @args [ CARD DEVICE ]
- @args.CARD {
- type string
- default "supersonic"
- }
- @args.DEVICE {
- type integer
- default 0
- }
- type hw
- card $CARD
- device $DEVICE
-}
-\endcode
-
-*/
+++ /dev/null
-/*! \page conffunc Configuration - runtime functions
-
-<P>The ALSA library accepts the runtime modification of configuration.
-The several build-in functions are available.</P>
-
-<P>The function is refered using id @func and function name. All other
-values in the current compound are used as configuration for the function.
-If compound func.<function_name> is defined in the root leafs, then library
-and function from this compound configuration is used, otherwise the prefix
-'snd_func_' is added to string and the code from the ALSA library is used.
-The definition of function looks like:</P>
-
-\code
-func.remove_first_char {
- lib "/usr/lib/libasoundextend.so"
- func "extend_remove_first_char"
-}
-\endcode
-
-\section conffunc_getenv The getenv function
-
-The getenv function allows to get an environment value. The vars values
-(array) defined the order and names for the environment values. When the
-first environment value is found, then the function replaces the whole
-compound by this result. If no value is found, then the default value is
-used, if defined.
-
-\code
- card {
- @func getenv
- vars [ MY_CARD CARD C ]
- default 0
- }
-\endcode
-
-\section conffunc_igetenv The igetenv function
-
-This function is same as getenv function, but the result value is converted
-to integer.
-
-\section conffunc_concat The concat function
-
-The concat function merges all given string in the array named string into
-one.
-
-\code
- filename {
- @func concat
- strings [
- "/usr/share"
- "/sound"
- "/a.wav"
- ]
- }
-\endcode
-
-\section conffunc_datadir The datadir function
-
-This function return the configuration data directory (usually /usr/share/alsa)
-as string as result. This function requires no other values.
-
-
-\section conffunc_refer The refer function
-
-This function substitutes the current compound with the compound named (key
-name, value string) and filename (key file - optional, value string).
-
-\code
- {
- @func refer
- file /etc/my-alsa.conf
- name pcm.lastone
- }
-\endcode
-
-\section conffunc_card_strtype The card_strtype function
-
-This function converts the given card number (key card, value integer) to card type
-(string).
-
-\section conffunc_card_id The card_id function
-
-This function returns the card id string for the given card number (key card, value
-integer).
-
-\section conffunc_pcm_id The pcm_id function
-
-This function returns the pcm id string for the given PCM device (key card,
-value integer; key device, value integer; key subdevice (optional), value
-integer).
-
-\section conffunc_private_string The private_string function
-
-This function returns the private data as string as result.
-
-\section conffunc_private_card_strtype The private_card_strtype function
-
-This function converts the private data (int) with card number to card type
-(string).
-
-\section conffunc_private_pcm_subdevice The private_pcm_subdevice function
-
-This functions returns the subdevice number for the pcm handle specified by
-the private data.
-
-*/
GENERATE_RTF = NO
CASE_SENSE_NAMES = NO
-INPUT = index.doxygen conf.doxygen confarg.doxygen \
- conffunc.doxygen pcm.doxygen \
+INPUT = index.doxygen \
../include/asoundlib.h \
../include/version.h \
../include/global.h \
+++ /dev/null
-/*! \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
- */
SND_CONFIG_TYPE_REAL,
/** Character string */
SND_CONFIG_TYPE_STRING,
+ /** Pointer - runtime only - cannot be saved */
+ SND_CONFIG_TYPE_POINTER,
/** Compound */
- SND_CONFIG_TYPE_COMPOUND,
+ SND_CONFIG_TYPE_COMPOUND = 1024,
} snd_config_type_t;
/** Config node handle */
/** Config compound iterator */
typedef struct _snd_config_iterator *snd_config_iterator_t;
+extern snd_config_t *snd_config;
+
int snd_config_top(snd_config_t **config);
int snd_config_load(snd_config_t *config, snd_input_t *in);
int snd_config_save(snd_config_t *config, snd_output_t *out);
+int snd_config_update(void);
int snd_config_search(snd_config_t *config, const char *key,
snd_config_t **result);
snd_config_t **result);
int snd_config_expand(snd_config_t *config, snd_config_t *root,
- const char *args, void *private_data,
+ const char *args, snd_config_t *private_data,
snd_config_t **result);
int snd_config_evaluate(snd_config_t *config, snd_config_t *root,
- void *private_data, snd_config_t **result);
+ snd_config_t *private_data, snd_config_t **result);
int snd_config_add(snd_config_t *config, snd_config_t *leaf);
int snd_config_delete(snd_config_t *config);
int snd_config_make_integer(snd_config_t **config, const char *key);
int snd_config_make_real(snd_config_t **config, const char *key);
int snd_config_make_string(snd_config_t **config, const char *key);
+int snd_config_make_pointer(snd_config_t **config, const char *key);
int snd_config_make_compound(snd_config_t **config, const char *key, int join);
+snd_config_type_t snd_config_get_type(snd_config_t *config);
+
int snd_config_set_id(snd_config_t *config, const char *id);
int snd_config_set_integer(snd_config_t *config, long value);
int snd_config_set_real(snd_config_t *config, double value);
int snd_config_set_string(snd_config_t *config, const char *value);
int snd_config_set_ascii(snd_config_t *config, const char *ascii);
+int snd_config_set_pointer(snd_config_t *config, const void *ptr);
+int snd_config_get_id(snd_config_t *config, const char **value);
int snd_config_get_integer(snd_config_t *config, long *value);
int snd_config_get_real(snd_config_t *config, double *value);
int snd_config_get_string(snd_config_t *config, const char **value);
int snd_config_get_ascii(snd_config_t *config, char **value);
+int snd_config_get_pointer(snd_config_t *config, const void **value);
+int snd_config_test_id(snd_config_t *config, const char *id);
snd_config_iterator_t snd_config_iterator_first(snd_config_t *node);
snd_config_iterator_t snd_config_iterator_next(snd_config_iterator_t iterator);
#define snd_config_for_each(pos, next, node) \
for (pos = snd_config_iterator_first(node), next = snd_config_iterator_next(pos); pos != snd_config_iterator_end(node); pos = next, next = snd_config_iterator_next(pos))
-snd_config_type_t snd_config_get_type(snd_config_t *config);
-const char *snd_config_get_id(snd_config_t *config);
-
-extern snd_config_t *snd_config;
-int snd_config_update(void);
-
/* Misc functions */
int snd_config_get_bool_ascii(const char *ascii);
int snd_card_get_name(int card, char **name);
int snd_card_get_longname(int card, char **name);
-int snd_sctl_build(snd_sctl_t **ctl, snd_ctl_t *handle, snd_config_t *config,
- void *private_data, int mode);
-int snd_sctl_free(snd_sctl_t *handle);
-int snd_sctl_install(snd_sctl_t *handle);
-int snd_sctl_remove(snd_sctl_t *handle);
-
int snd_ctl_open(snd_ctl_t **ctl, const char *name, int mode);
int snd_ctl_close(snd_ctl_t *ctl);
int snd_ctl_nonblock(snd_ctl_t *ctl, int nonblock);
/** \} */
+/**
+ * \defgroup SControl Setup Control Interface
+ * \ingroup Control
+ * The setup control interface - set or modify control elements from a configuration file.
+ * \{
+ */
+
+int snd_sctl_build(snd_sctl_t **ctl, snd_ctl_t *handle, snd_config_t *config,
+ snd_config_t *private_data, int mode);
+int snd_sctl_free(snd_sctl_t *handle);
+int snd_sctl_install(snd_sctl_t *handle);
+int snd_sctl_remove(snd_sctl_t *handle);
+
+/** \} */
+
#ifdef __cplusplus
}
#endif
#endif /* __ALSA_CONTROL_H */
-
#define __ALSA_GLOBAL_H_
/**
- * \defgroup Global Global defines
- * Global defines
+ * \defgroup Global Global defines and functions
+ * Global defines and functions.
* \{
*/
#ifndef ATTRIBUTE_UNUSED
-#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) /**< don't print warning when attribute is not used */
+/** do not print warning (gcc) when function parameter is not used */
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#endif
#ifdef PIC /* dynamic build */
snd_async_callback_t callback, void *private_data);
int snd_async_del_handler(snd_async_handler_t *handler);
int snd_async_handler_get_fd(snd_async_handler_t *handler);
+int snd_async_handler_get_signo(snd_async_handler_t *handler);
void *snd_async_handler_get_callback_private(snd_async_handler_t *handler);
/** \} */
#endif /* __ALSA_GLOBAL_H */
-
#define SND_BIG_ENDIAN
#endif
-extern int snd_async_signo;
-
struct _snd_async_handler {
enum {
SND_ASYNC_HANDLER_GENERIC,
* \author Takashi Iwai <tiwai@suse.de>
* \date 1998-2001
*
- * Application interface library for the ALSA driver
+ * Application interface library for the ALSA driver.
+ * See the \ref pcm page for more details.
*
*
* This library is free software; you can redistribute it and/or modify
/**
* \defgroup PCM PCM Interface
- * The PCM Interface.
+ * See the \ref pcm page for more details.
* \{
*/
/** PCM class */
typedef enum _snd_pcm_class {
/** standard device */
+
SND_PCM_CLASS_GENERIC = 0,
/** multichannel device */
SND_PCM_CLASS_MULTI,
/**
* \defgroup PCM_Info Stream Information
- * PCM Stream Information
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_HW_Params Hardware Parameters
- * PCM Hardware Parameters
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_SW_Params Software Parameters
- * PCM Software Parameters
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_Access Access Mask Functions
- * PCM Access Mask Functions
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_Format Format Mask Functions
- * PCM Format Mask Functions
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_SubFormat Subformat Mask Functions
- * PCM Subformat Mask Functions
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_Status Status Functions
- * PCM Status Functions
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_Description Description Functions
- * PCM Description Functions
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_Dump Debug Functions
- * PCM Debug Functions
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_Direct Direct Access (MMAP) Functions
- * PCM Direct Access (MMAP) Functions
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_Helpers Helper Functions
- * PCM Helper Functions
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_Hook Hook Extension
- * PCM Hook Extension
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_Scope Scope Plugin Extension
- * PCM Scope Plugin Extension
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
/**
* \defgroup PCM_Deprecated Deprecated Functions
- * PCM Deprecated Functions
* \ingroup PCM
+ * See the \ref pcm page for more details.
* \{
*/
#endif
#endif /* __ALSA_PCM_H */
-
#ifdef SND_ASYNC_RT_SIGNAL
/** async signal number */
-int snd_async_signo;
+static int snd_async_signo;
+
void snd_async_init(void) __attribute__ ((constructor));
void snd_async_init(void)
}
#else
/** async signal number */
-int snd_async_signo = SIGIO;
+static int snd_async_signo = SIGIO;
#endif
static LIST_HEAD(snd_async_handlers);
* \param callback - Async callback
* \param private_data - Private data for async callback
* \result zero if success, otherwise a negative error code
+ *
+ * The function create the async handler. The ALSA extension
+ * for the standard SIGIO signal contains the multiplexer
+ * for multiple asynchronous notifiers using one sigaction
+ * callback.
*/
int snd_async_add_handler(snd_async_handler_t **handler, int fd,
snd_async_callback_t callback, void *private_data)
{
snd_async_handler_t *h;
int was_empty;
+ assert(handler);
h = malloc(sizeof(*h));
if (!h)
return -ENOMEM;
int snd_async_del_handler(snd_async_handler_t *handler)
{
int err = 0;
+ assert(handler);
list_del(&handler->glist);
if (list_empty(&snd_async_handlers)) {
struct sigaction act;
return err;
}
+/**
+ * \brief Get signal number assigned to async handler
+ * \param handler Async handler
+ * \result signal number if success, otherwise a negative error code
+ */
+int snd_async_handler_get_signo(snd_async_handler_t *handler)
+{
+ assert(handler);
+ return snd_async_signo;
+}
+
/**
* \brief Get file descriptor assigned to async handler
* \param handler Async handler
*/
int snd_async_handler_get_fd(snd_async_handler_t *handler)
{
+ assert(handler);
return handler->fd;
}
*/
void *snd_async_handler_get_callback_private(snd_async_handler_t *handler)
{
+ assert(handler);
return handler->private_data;
}
* \author Jaroslav Kysela <perex@suse.cz>
* \date 2000-2001
*
- * Generic stdio-like input interface
+ * Tree based, full nesting configuration functions.
*/
/*
* Configuration helper functions
*
*/
+/*! \page conf Configuration files
+
+<P>Configuration files are using a simple format allowing the modern
+data description like nesting and array assignments.</P>
+
+\section conf_whitespace Whitespace
+
+Whitespace is the collective name given to spaces (blanks), horizontal and
+vertical tabs, newline characters, and comments. Whitespace can serve to
+indicate where configuration tokens start and end, but beyond this function,
+any surplus whitespace is discarded. For example, the two sequences
+
+\code
+ a 1 b 2
+\endcode
+
+and
+
+\code
+ a 1
+ b 2
+\endcode
+
+are lexically equivalent and parse identically to give the four tokens:
+
+\code
+a
+1
+b
+2
+\endcode
+
+The ASCII characters representing whitespace can occur within literal
+strings, int which case they are protected from the normal parsing process
+(tey remain as part of the string). For example:
+
+\code
+ name "John Smith"
+\endcode
+
+parses to two tokens, including the single literal-string token "John
+Smith".
+
+\section conf_linesplicing Line splicing with \
+
+A special case occurs, if the final newline character encountered is
+preceded by a backslash (\) in the string value definition. The backslash
+and new line are both discarded, allowing two physical lines of text to be
+treated as one unit.
+
+\code
+"John \
+Smith"
+\endcode
+
+is parsed as "John Smith".
+
+\section conf_comments Comments
+
+A single-line comments are defined using character #. The comment can start
+in any position, and extends until the next new line.
+
+\code
+ a 1 # this is a comment
+\endcode
+
+\section conf_include Include another configuration file
+
+A new configuration file can be included using <filename> syntax. The global
+configuration directory can be referenced using <confdir:filename> syntax.
+
+\code
+</etc/alsa1.conf>
+<confdir:pcm/surround.conf>
+\endcode
+
+\section conf_punctuators Punctuators
+
+The configuration punctuators (also known as separators) are:
+
+\code
+ {} [] , ; = . ' " new-line form-feed carriage-return whitespace
+\endcode
+
+\subsection conf_braces Braces
+
+Open and close braces { } indicate the start and end of a compound
+statement:
+
+\code
+a {
+ b 1
+}
+\endcode
+
+\subsection conf_brackets Brackets
+
+Open and close brackets indicate single array definition. The identificators
+are automatically generated starting with zero.
+
+\code
+a [
+ "first"
+ "second"
+]
+\endcode
+
+Above code is equal to
+
+\code
+a.0 "first"
+a.1 "second"
+\endcode
+
+\subsection conf_comma_semicolon Comma and semicolon
+
+The comma (,) or semicolon (;) can separate the value assignments. It is not
+strictly required to use these separators, because any whitespace supplies
+them.
+
+\code
+a 1;
+b 1,
+\endcode
+
+\subsection conf_equal Equal sign
+
+The equal sign (=) separates can separate variable declarations from
+initialization lists:
+
+\code
+a=1
+b=2
+\endcode
+
+Using the equal signs is not required, because any whitespace supplies
+them.
+
+\section conf_assigns Assigns
+
+The configuration file defines id (key) and value pairs. The id (key) can be
+composed from any ASCII digits or chars from a to z or A to Z, including
+char _. The value can be either a string, integer or real number.
+
+\subsection conf_single Single assign
+
+\code
+a 1 # is equal to
+a=1 # is equal to
+a=1; # is equal to
+a 1,
+\endcode
+
+\subsection conf_compound Compound assign (definition using braces)
+
+\code
+a {
+ b = 1
+}
+a={
+ b 1,
+}
+\endcode
+
+\section conf_compound1 Compound assign (one key definition)
+
+\code
+a.b 1
+a.b=1
+\endcode
+
+\subsection conf_array Array assign (definition using brackets)
+
+\code
+a [
+ "first"
+ "second"
+]
+\endcode
+
+\subsection conf_array1 Array assign (one key definition)
+
+\code
+a.0 "first"
+a.1 "second"
+\endcode
+
+\section conf_summary Summary
+
+\code
+# Configuration file syntax
+
+# Include a new configuration file
+<filename>
+
+# Simple assign
+name [=] value [,|;]
+
+# Compound assign (first style)
+name [=] {
+ name1 [=] value [,|;]
+ ...
+}
+
+# Compound assign (second style)
+name.name1 [=] value [,|;]
+
+# Array assign (first style)
+name [
+ value0 [,|;]
+ value1 [,|;]
+ ...
+]
+
+# Array assign (second style)
+name.0 [=] value0 [,|;]
+name.1 [=] value1 [,|;]
+\endcode
+
+*/
+
+/*! \page confarg Configuration - runtime arguments
+
+<P>The ALSA library can accept runtime arguments for some configuration
+blocks. This extension is on top of the basic syntax of the configuration
+files.<P>
+
+\section confarg_define Defining arguments
+
+Arguments are specified by id (key) @args and array values containing
+the string names of arguments:
+
+\code
+@args [ CARD ] # or
+@args.0 CARD
+\endcode
+
+\section confarg_type Defining argument type and default value
+
+Arguments type is specified by id (key) @args and argument name. The type
+and default value is specified in the compound:
+
+\code
+@args.CARD {
+ type string
+ default "abcd"
+}
+\endcode
+
+\section confarg_refer Refering argument
+
+Arguments are refered by dollar-sign ($) and name of argument:
+
+\code
+ card $CARD
+\endcode
+
+\section confarg_example Example
+
+\code
+pcm.demo {
+ @args [ CARD DEVICE ]
+ @args.CARD {
+ type string
+ default "supersonic"
+ }
+ @args.DEVICE {
+ type integer
+ default 0
+ }
+ type hw
+ card $CARD
+ device $DEVICE
+}
+\endcode
+
+*/
+
+/*! \page conffunc Configuration - runtime functions
+
+<P>The ALSA library accepts the runtime modification of configuration.
+The several build-in functions are available.</P>
+
+<P>The function is refered using id @func and function name. All other
+values in the current compound are used as configuration for the function.
+If compound func.<function_name> is defined in the root leafs, then library
+and function from this compound configuration is used, otherwise the prefix
+'snd_func_' is added to string and the code from the ALSA library is used.
+The definition of function looks like:</P>
+
+\code
+func.remove_first_char {
+ lib "/usr/lib/libasoundextend.so"
+ func "extend_remove_first_char"
+}
+\endcode
+
+*/
+
+
#include <stdarg.h>
#include <wordexp.h>
#include <dlfcn.h>
long integer;
char *string;
double real;
+ const void *ptr;
struct {
struct list_head fields;
int join;
case SND_CONFIG_TYPE_STRING:
string_print(n->u.string, 0, out);
break;
+ case SND_CONFIG_TYPE_POINTER:
+ SNDERR("cannot save runtime pointer type");
+ return -EINVAL;
case SND_CONFIG_TYPE_COMPOUND:
snd_output_putc(out, '{');
snd_output_putc(out, '\n');
/**
* \brief Return id of a config node
* \param config Config node handle
- * \return node id
+ * \param value The result id
+ * \return 0 on success otherwise a negative error code
*/
-const char *snd_config_get_id(snd_config_t *config)
+int snd_config_get_id(snd_config_t *config, const char **id)
{
- return config->id;
+ assert(config && id);
+ *id = config->id;
+ return 0;
}
/**
return snd_config_make(config, id, SND_CONFIG_TYPE_STRING);
}
+/**
+ * \brief Build a pointer config node
+ * \param config Returned config node handle pointer
+ * \param id Node id
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_config_make_pointer(snd_config_t **config, const char *id)
+{
+ return snd_config_make(config, id, SND_CONFIG_TYPE_POINTER);
+}
+
/**
* \brief Build an empty compound config node
* \param config Returned config node handle pointer
return 0;
}
+/**
+ * \brief Change the value of a pointer config node
+ * \param config Config node handle
+ * \param ptr Value
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_config_set_pointer(snd_config_t *config, const void *value)
+{
+ assert(config);
+ if (config->type != SND_CONFIG_TYPE_POINTER)
+ return -EINVAL;
+ config->u.ptr = value;
+ return 0;
+}
+
/**
* \brief Change the value of a config node
* \param config Config node handle
return 0;
}
+/**
+ * \brief Get the value of a pointer config node
+ * \param config Config node handle
+ * \param ptr Returned value pointer
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_config_get_pointer(snd_config_t *config, const void **ptr)
+{
+ assert(config && ptr);
+ if (config->type != SND_CONFIG_TYPE_POINTER)
+ return -EINVAL;
+ *ptr = config->u.ptr;
+ return 0;
+}
+
/**
* \brief Get the value in ASCII form
* \param config Config node handle
return 0;
}
+/**
+ * \brief Compare the config node id and given ASCII id
+ * \param config Config node handle
+ * \param id ASCII id
+ * \return the same value as result of the strcmp function
+ */
+int snd_config_test_id(snd_config_t *config, const char *id)
+{
+ assert(config && id);
+ return strcmp(config->id, id);
+}
+
/**
* \brief Dump a config tree contents
* \param config Config node handle
*/
int snd_config_search_hooks(snd_config_t *config, const char *key, snd_config_t **result)
{
- static int snd_config_hooks(snd_config_t *config, void *private_data);
+ static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data);
SND_CONFIG_SEARCH(config, key, result, \
err = snd_config_hooks(config, NULL); \
if (err < 0) \
*/
int snd_config_searcha_hooks(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result)
{
- static int snd_config_hooks(snd_config_t *config, void *private_data);
+ static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data);
SND_CONFIG_SEARCHA(root, config, key, result,
snd_config_searcha_hooks,
err = snd_config_hooks(config, NULL); \
static unsigned int files_info_count = 0;
-static int snd_config_hooks_call(snd_config_t *root, snd_config_t *config, void *private_data)
+static int snd_config_hooks_call(snd_config_t *root, snd_config_t *config, snd_config_t *private_data)
{
void *h = NULL;
snd_config_t *c, *func_conf = NULL;
char *buf = NULL;
const char *lib = NULL, *func_name = NULL;
const char *str;
- int (*func)(snd_config_t *root, snd_config_t *config, snd_config_t **dst, void *private_data) = NULL;
+ int (*func)(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data) = NULL;
int err;
err = snd_config_search(config, "func", &c);
}
snd_config_for_each(i, next, func_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id = n->id;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
return 0;
}
-static int snd_config_hooks(snd_config_t *config, void *private_data)
+static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data)
{
snd_config_t *n;
snd_config_iterator_t i, next;
hit = 0;
snd_config_for_each(i, next, n) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id = n->id;
long i;
err = safe_strtol(id, &i);
if (err < 0) {
* \param private_data Private data
* \return zero if success, otherwise a negative error code
*/
-int snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t **dst, void *private_data)
+int snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data)
{
snd_config_t *n, *res = NULL;
snd_config_iterator_t i, next;
snd_config_t *c = snd_config_iterator_entry(i);
const char *str;
if ((err = snd_config_get_string(c, &str)) < 0) {
- SNDERR("Field %s is not a string", snd_config_get_id(c));
+ SNDERR("Field %s is not a string", c->id);
goto _err;
}
fi_count++;
hit = 0;
snd_config_for_each(i, next, n) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id = n->id;
long i;
err = safe_strtol(id, &i);
if (err < 0) {
* \param private_data Private data
* \return zero if success, otherwise a negative error code
*/
-int snd_config_hook_load_for_all_cards(snd_config_t *root, snd_config_t *config, snd_config_t **dst, void *private_data ATTRIBUTE_UNUSED)
+int snd_config_hook_load_for_all_cards(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data ATTRIBUTE_UNUSED)
{
int card = -1, err;
if (err < 0)
return err;
if (card >= 0) {
- snd_config_t *n;
+ snd_config_t *n, *private_data = NULL;
const char *driver;
char *fdriver = NULL;
err = snd_determine_driver(card, &fdriver);
if (err < 0)
return err;
+ err = snd_config_make_string(&private_data, "string");
+ if (err < 0)
+ goto __err;
+ snd_config_set_string(private_data, fdriver);
if (snd_config_search(root, fdriver, &n) >= 0) {
if (snd_config_get_string(n, &driver) < 0)
continue;
} else {
driver = fdriver;
}
- err = snd_config_hook_load(root, config, &n, (void *)driver);
+ err = snd_config_hook_load(root, config, &n, private_data);
+ __err:
+ if (private_data)
+ snd_config_delete(private_data);
if (fdriver)
free(fdriver);
if (err < 0)
snd_config_t *root,
snd_config_t **dst,
snd_config_walk_pass_t pass,
- void *private_data);
+ snd_config_t *private_data);
#endif
static int snd_config_walk(snd_config_t *src,
snd_config_t *root,
snd_config_t **dst,
snd_config_walk_callback_t callback,
- void *private_data)
+ snd_config_t *private_data)
{
int err;
snd_config_iterator_t i, next;
snd_config_t *root ATTRIBUTE_UNUSED,
snd_config_t **dst,
snd_config_walk_pass_t pass,
- void *private_data ATTRIBUTE_UNUSED)
+ snd_config_t *private_data ATTRIBUTE_UNUSED)
{
int err;
- const char *id = snd_config_get_id(src);
+ const char *id = src->id;
snd_config_type_t type = snd_config_get_type(src);
switch (pass) {
case SND_CONFIG_WALK_PASS_PRE:
snd_config_t *root ATTRIBUTE_UNUSED,
snd_config_t **dst,
snd_config_walk_pass_t pass,
- void *private_data)
+ snd_config_t *private_data)
{
int err;
- const char *id = snd_config_get_id(src);
+ const char *id = src->id;
snd_config_type_t type = snd_config_get_type(src);
switch (pass) {
case SND_CONFIG_WALK_PASS_PRE:
snd_config_t *root,
snd_config_t **dst ATTRIBUTE_UNUSED,
snd_config_walk_pass_t pass,
- void *private_data)
+ snd_config_t *private_data)
{
int err;
if (pass == SND_CONFIG_WALK_PASS_PRE) {
const char *lib = NULL, *func_name = NULL;
const char *str;
int (*func)(snd_config_t **dst, snd_config_t *root,
- snd_config_t *src, void *private_data) = NULL;
+ snd_config_t *src, snd_config_t *private_data) = NULL;
void *h = NULL;
snd_config_t *c, *func_conf = NULL;
err = snd_config_search(src, "@func", &c);
}
snd_config_for_each(i, next, func_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id = n->id;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
* \return zero if success, otherwise a negative error code
*/
int snd_config_evaluate(snd_config_t *config, snd_config_t *root,
- void *private_data, snd_config_t **result)
+ snd_config_t *private_data, snd_config_t **result)
{
/* FIXME: Only in place evaluation is currently implemented */
assert(result == NULL);
continue;
snd_config_for_each(f, fnext, def) {
snd_config_t *fld = snd_config_iterator_entry(f);
- const char *id = snd_config_get_id(fld);
+ const char *id = fld->id;
if (strcmp(id, "type") == 0)
continue;
if (strcmp(id, "default") == 0) {
err = snd_config_copy(&deflt, fld);
if (err < 0)
return err;
- err = snd_config_set_id(deflt, snd_config_get_id(def));
+ err = snd_config_set_id(deflt, def->id);
if (err < 0) {
snd_config_delete(deflt);
return err;
snd_config_for_each(i, next, subs) {
snd_config_t *n = snd_config_iterator_entry(i);
snd_config_t *d;
- const char *id = snd_config_get_id(n);
+ const char *id = n->id;
err = snd_config_search(defs, id, &d);
if (err < 0) {
SNDERR("Unknown parameter %s", id);
err = -EINVAL;
goto _err;
}
- var = snd_config_get_id(def);
+ var = def->id;
err = snd_config_search(subs, var, &sub);
if (err >= 0)
snd_config_delete(sub);
* \return 0 on success otherwise a negative error code
*/
int snd_config_expand(snd_config_t *config, snd_config_t *root, const char *args,
- void *private_data, snd_config_t **result)
+ snd_config_t *private_data, snd_config_t **result)
{
int err;
snd_config_t *defs, *subs = NULL, *res;
strings [
"cards."
{
- @func card_strtype
+ @func card_driver
card $CARD
}
".pcm.center_lfe." $DEV ":CARD=" $CARD
strings [
"cards."
{
- @func card_strtype
+ @func card_driver
card $CARD
}
".pcm.front." $DEV ":CARD=" $CARD
strings [
"cards."
{
- @func card_strtype
+ @func card_driver
card $CARD
}
".pcm.iec958." $DEV ":"
strings [
"cards."
{
- @func card_strtype
+ @func card_driver
card $CARD
}
".pcm.rear." $DEV ":CARD=" $CARD
strings [
"cards."
{
- @func card_strtype
+ @func card_driver
card $CARD
}
".pcm.surround40." $DEV ":CARD=" $CARD
strings [
"cards."
{
- @func card_strtype
+ @func card_driver
card $CARD
}
".pcm.surround51." $DEV ":CARD=" $CARD
+/**
+ * \file confmisc.c
+ * \brief Configuration helper functions
+ * \author Abramo Bagnara <abramo@alsa-project.org>
+ * \author Jaroslav Kysela <perex@suse.cz>
+ * \date 2000-2001
+ *
+ * Configuration helper functions.
/*
* Miscellaneous configuration helper functions
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>,
*
*/
+/*! \page conffunc
+
+\section Function reference
+
+<UL>
+ <LI>The getenv function - snd_func_getenv() - allows to obtain
+ an environment value. The result is string.
+ <LI>The igetenv function - snd_func_igetenv() - allows to obtain
+ an environment value. The result is integer.
+ <LI>The concat function - snd_func_concat() - merges all specified
+ strings. The result is string.
+ <LI>The datadir function - snd_func_datadir() - returns the
+ data directory. The result is string.
+ <LI>The refer function - snd_func_refer() - copies the refered
+ configuration. The result is same as the refered node.
+ <LI>The card_driver function - snd_func_card_driver() - returns
+ the driver identification. The result is string.
+ <LI>The card_id function - snd_func_card_id() - returns
+ the card identification. The result is string.
+ <LI>The pcm_id function - snd_func_pcm_id() - returns
+ the pcm identification. The result is string.
+ <LI>The private_string - snd_func_private_string() - returns
+ string using private_data node.
+ <LI>The private_card_driver - snd_func_private_card_driver() -
+ returns the driver identification using private_data node.
+ The result is string.
+ <LI>The private_pcm_subdevice - snd_func_private_pcm_subdevice() -
+ returns the PCM subdevice number using the private_data node.
+ The result is string.
+</UL>
+
+*/
+
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int snd_config_get_bool(snd_config_t *conf)
{
long v;
- const char *str;
+ const char *str, *id;
int err;
+ err = snd_config_get_id(conf, &id);
+ if (err < 0)
+ return err;
err = snd_config_get_integer(conf, &v);
if (err >= 0) {
if (v < 0 || v > 1) {
_invalid_value:
- SNDERR("Invalid value for %s", snd_config_get_id(conf));
+ SNDERR("Invalid value for %s", id);
return -EINVAL;
}
return v;
}
err = snd_config_get_string(conf, &str);
if (err < 0) {
- SNDERR("Invalid type for %s", snd_config_get_id(conf));
+ SNDERR("Invalid type for %s", id);
return -EINVAL;
}
err = snd_config_get_bool_ascii(str);
int snd_config_get_ctl_iface(snd_config_t *conf)
{
long v;
- const char *str;
+ const char *str, *id;
int err;
+
+ err = snd_config_get_id(conf, &id);
+ if (err < 0)
+ return err;
err = snd_config_get_integer(conf, &v);
if (err >= 0) {
if (v < 0 || v > SND_CTL_ELEM_IFACE_LAST) {
_invalid_value:
- SNDERR("Invalid value for %s", snd_config_get_id(conf));
+ SNDERR("Invalid value for %s", id);
return -EINVAL;
}
return v;
}
err = snd_config_get_string(conf, &str);
if (err < 0) {
- SNDERR("Invalid type for %s", snd_config_get_id(conf));
+ SNDERR("Invalid type for %s", id);
return -EINVAL;
}
err = snd_config_get_ctl_iface_ascii(str);
* Helper functions for the configuration file
*/
-int snd_func_getenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data)
+/**
+ * \brief Get environment value
+ * \param dst The destination node (result type is string)
+ * \param root The root source node
+ * \param src The source node, with vars and default definition
+ * \param private_data The private_data node
+ * \return a positive value when success otherwise a negative error number
+ *
+ * Example:
+\code
+ {
+ @func getenv
+ vars [ MY_CARD CARD C ]
+ default 0
+ }
+\endcode
+ */
+int snd_func_getenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
+ snd_config_t *private_data)
{
snd_config_t *n, *d;
snd_config_iterator_t i, next;
hit = 0;
snd_config_for_each(i, next, n) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
- const char *ptr, *env;
+ const char *id, *ptr, *env;
long i;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) {
SNDERR("field %s is not a string", id);
err = -EINVAL;
__ok:
err = res == NULL ? -ENOMEM : 0;
if (err >= 0) {
- err = snd_config_make_string(dst, snd_config_get_id(src));
- if (err >= 0)
- snd_config_set_string(*dst, res);
+ const char *id;
+ err = snd_config_get_id(src, &id);
+ if (err >= 0) {
+ err = snd_config_make_string(dst, id);
+ if (err >= 0)
+ snd_config_set_string(*dst, res);
+ }
free(res);
}
__error:
free(def);
return err;
}
+#ifndef DOC_HIDDEN
SND_DLSYM_BUILD_VERSION(snd_func_getenv, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#endif
-int snd_func_igetenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data)
+/**
+ * \brief Get integer environment value
+ * \param dst The destination node (result type is integer)
+ * \param root The root source node
+ * \param src The source node, with vars and default definition
+ * \param private_data The private_data node
+ * \return a positive value when success otherwise a negative error number
+ *
+ * Example:
+\code
+ {
+ @func getenv
+ vars [ MY_DEVICE DEVICE D ]
+ default 0
+ }
+\endcode
+ */
+int snd_func_igetenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
+ snd_config_t *private_data)
{
snd_config_t *d;
- const char *str;
+ const char *str, *id;
int err;
long v;
+
err = snd_func_getenv(&d, root, src, private_data);
if (err < 0)
return err;
err = snd_config_get_string(d, &str);
if (err < 0)
- goto _end;
+ return err;
err = safe_strtol(str, &v);
if (err < 0)
- goto _end;
- err = snd_config_make_integer(dst, snd_config_get_id(src));
+ return err;;
+ err = snd_config_get_id(src, &id);
if (err < 0)
- goto _end;
+ return err;
+ err = snd_config_make_integer(dst, id);
+ if (err < 0)
+ return err;
snd_config_set_integer(*dst, v);
- err = 0;
-
- _end:
- return err;
+ return 0;
}
+#ifndef DOC_HIDDEN
SND_DLSYM_BUILD_VERSION(snd_func_igetenv, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#endif
-int snd_func_concat(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data)
+/**
+ * \brief Merge given strings
+ * \param dst The destination node (result type is string)
+ * \param root The root source node
+ * \param src The source node, with strings definition
+ * \param private_data The private_data node
+ * \return a positive value when success otherwise a negative error number
+ *
+ * Example (result is string "a1b2c3" ]:
+\code
+ {
+ @func concat
+ strings [ "a1" "b2" "c3" ]
+ default 0
+ }
+\endcode
+ */
+int snd_func_concat(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
+ snd_config_t *private_data)
{
snd_config_t *n;
snd_config_iterator_t i, next;
+ const char *id;
char *res = NULL, *tmp;
int idx = 0, len = 0, len1, err, hit;
snd_config_for_each(i, next, n) {
snd_config_t *n = snd_config_iterator_entry(i);
char *ptr;
- const char *id = snd_config_get_id(n);
+ const char *id;
long i;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
err = safe_strtol(id, &i);
if (err < 0) {
SNDERR("id of field %s is not an integer", id);
err = -EINVAL;
goto __error;
}
- err = snd_config_make_string(dst, snd_config_get_id(src));
- if (err >= 0)
- snd_config_set_string(*dst, res);
+ err = snd_config_get_id(src, &id);
+ if (err >= 0) {
+ err = snd_config_make_string(dst, id);
+ if (err >= 0)
+ snd_config_set_string(*dst, res);
+ }
free(res);
__error:
return err;
}
+#ifndef DOC_HIDDEN
SND_DLSYM_BUILD_VERSION(snd_func_concat, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#endif
+/**
+ * \brief Get data directory
+ * \param dst The destination node (result type is string)
+ * \param root The root source node
+ * \param src The source node
+ * \param private_data The private_data node (unused)
+ * \return a positive value when success otherwise a negative error number
+ *
+ * Example (result is "/usr/share/alsa" using default paths):
+\code
+ {
+ @func datadir
+ }
+\endcode
+ */
int snd_func_datadir(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED,
- snd_config_t *src, void *private_data ATTRIBUTE_UNUSED)
+ snd_config_t *src, snd_config_t *private_data ATTRIBUTE_UNUSED)
{
- int err = snd_config_make_string(dst, snd_config_get_id(src));
+ int err;
+ const char *id;
+
+ err = snd_config_get_id(src, &id);
+ if (err < 0)
+ return err;
+ err = snd_config_make_string(dst, id);
if (err >= 0)
err = snd_config_set_string(*dst, DATADIR "/alsa");
- return 0;
+ return err;
}
+#ifndef DOC_HIDDEN
SND_DLSYM_BUILD_VERSION(snd_func_datadir, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#endif
static int open_ctl(long card, snd_ctl_t **ctl)
{
}
#endif
-int snd_func_private_string(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *src, void *private_data)
+/**
+ * \brief Get string from private_data
+ * \param dst The destination node (result type is string)
+ * \param root The root source node
+ * \param src The source node
+ * \param private_data The private_data node (type string, id == "string")
+ * \return a positive value when success otherwise a negative error number
+ *
+ * Example:
+\code
+ {
+ @func private_string
+ }
+\endcode
+ */
+int snd_func_private_string(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED,
+ snd_config_t *src, snd_config_t *private_data)
{
int err;
+ snd_config_t *n;
+ const char *str, *id;
if (private_data == NULL)
return snd_config_copy(dst, src);
- err = snd_config_make_string(dst, snd_config_get_id(src));
- if (err >= 0)
- err = snd_config_set_string(*dst, (char *)private_data);
+ err = snd_config_test_id(private_data, "string");
+ if (err) {
+ SNDERR("field string not found");
+ return -EINVAL;
+ }
+ err = snd_config_get_string(private_data, &str);
+ if (err < 0) {
+ SNDERR("field string is not a string");
+ return err;
+ }
+ err = snd_config_get_id(src, &id);
+ if (err >= 0) {
+ err = snd_config_make_string(dst, id);
+ if (err >= 0)
+ err = snd_config_set_string(*dst, str);
+ }
return err;
}
+#ifndef DOC_HIDDEN
SND_DLSYM_BUILD_VERSION(snd_func_private_string, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#endif
+#ifndef DOC_HIDDEN
int snd_determine_driver(int card, char **driver)
{
snd_ctl_t *ctl = NULL;
snd_ctl_close(ctl);
return err;
}
+#endif
-int snd_func_private_card_strtype(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *src, void *private_data)
+/**
+ * \brief Get driver identification using private_data
+ * \param dst The destination node (result type is string)
+ * \param root The root source node
+ * \param src The source node
+ * \param private_data The private_data node (type = integer, id = "card")
+ * \return a positive value when success otherwise a negative error number
+ *
+ * Example:
+\code
+ {
+ @func private_card_driver
+ }
+\endcode
+ */
+int snd_func_private_card_driver(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *src,
+ snd_config_t *private_data)
{
char *driver;
+ snd_config_t *n;
+ const char *id;
int err;
+ long card;
- if ((err = snd_determine_driver((long)private_data, &driver)) < 0)
+ err = snd_config_test_id(private_data, "card");
+ if (err) {
+ SNDERR("field card not found");
+ return -EINVAL;
+ }
+ err = snd_config_get_integer(n, &card);
+ if (err < 0) {
+ SNDERR("field card is not an integer");
return err;
- err = snd_config_make_string(dst, snd_config_get_id(src));
- if (err >= 0)
- err = snd_config_set_string(*dst, driver);
+ }
+ if ((err = snd_determine_driver(card, &driver)) < 0)
+ return err;
+ err = snd_config_get_id(src, &id);
+ if (err >= 0) {
+ err = snd_config_make_string(dst, id);
+ if (err >= 0)
+ err = snd_config_set_string(*dst, driver);
+ }
free(driver);
return err;
}
-SND_DLSYM_BUILD_VERSION(snd_func_private_card_strtype, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#ifndef DOC_HIDDEN
+SND_DLSYM_BUILD_VERSION(snd_func_private_card_driver, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#endif
-int snd_func_card_strtype(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data)
+/**
+ * \brief Get driver identification
+ * \param dst The destination node (result type is string)
+ * \param root The root source node
+ * \param src The source node
+ * \param private_data The private_data node
+ * \return a positive value when success otherwise a negative error number
+ *
+ * Example:
+\code
+ {
+ @func card_driver
+ card 0
+ }
+\endcode
+ */
+int snd_func_card_driver(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
+ snd_config_t *private_data)
{
- snd_config_t *n;
+ snd_config_t *n, *val;
char *str;
long v;
int err;
return v;
}
free(str);
- return snd_func_private_card_strtype(dst, root, src, (void *)v);
+ err = snd_config_make_integer(&val, "card");
+ if (err < 0)
+ return err;
+ snd_config_set_integer(val, v);
+ err = snd_func_private_card_driver(dst, root, src, val);
+ snd_config_delete(val);
+ return err;
}
-SND_DLSYM_BUILD_VERSION(snd_func_card_strtype, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#ifndef DOC_HIDDEN
+SND_DLSYM_BUILD_VERSION(snd_func_card_driver, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#endif
-int snd_func_card_id(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data)
+/**
+ * \brief Get card identification
+ * \param dst The destination node (result type is string)
+ * \param root The root source node
+ * \param src The source node
+ * \param private_data The private_data node
+ * \return a positive value when success otherwise a negative error number
+ *
+ * Example:
+\code
+ {
+ @func card_id
+ card 0
+ }
+\endcode
+ */
+int snd_func_card_id(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
+ snd_config_t *private_data)
{
snd_config_t *n;
char *res = NULL;
snd_ctl_t *ctl = NULL;
snd_ctl_card_info_t *info;
+ const char *id;
long v;
int err;
err = -ENOMEM;
goto __error;
}
- err = snd_config_make_string(dst, snd_config_get_id(src));
- if (err >= 0)
- err = snd_config_set_string(*dst, res);
+ err = snd_config_get_id(src, &id);
+ if (err >= 0) {
+ err = snd_config_make_string(dst, id);
+ if (err >= 0)
+ err = snd_config_set_string(*dst, res);
+ }
free(res);
__error:
if (ctl)
snd_ctl_close(ctl);
return err;
}
+#ifndef DOC_HIDDEN
SND_DLSYM_BUILD_VERSION(snd_func_card_id, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#endif
+/**
+ * \brief Get pcm identification
+ * \param dst The destination node (result type is string)
+ * \param root The root source node
+ * \param src The source node
+ * \param private_data The private_data node
+ * \return a positive value when success otherwise a negative error number
+ *
+ * Example:
+\code
+ {
+ @func pcm_id
+ card 0
+ device 0
+ subdevice 0 # optional
+ }
+\endcode
+ */
int snd_func_pcm_id(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data)
{
snd_config_t *n;
snd_ctl_t *ctl = NULL;
snd_pcm_info_t *info;
+ const char *id;
long card, device, subdevice = 0;
int err;
SNDERR("snd_ctl_pcm_info error: %s", snd_strerror(err));
goto __error;
}
- err = snd_config_make_string(dst, snd_config_get_id(src));
- if (err >= 0)
- err = snd_config_set_string(*dst, snd_pcm_info_get_id(info));
+ err = snd_config_get_id(src, &id);
+ if (err >= 0) {
+ err = snd_config_make_string(dst, id);
+ if (err >= 0)
+ err = snd_config_set_string(*dst, snd_pcm_info_get_id(info));
+ }
__error:
if (ctl)
snd_ctl_close(ctl);
return err;
}
+#ifndef DOC_HIDDEN
SND_DLSYM_BUILD_VERSION(snd_func_pcm_id, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#endif
-int snd_func_private_pcm_subdevice(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *src, void *private_data)
+/**
+ * \brief Get pcm subdevice using private_data
+ * \param dst The destination node (result type is integer)
+ * \param root The root source node
+ * \param src The source node
+ * \param private_data The private_data node (type = pointer, id = "pcm_handle")
+ * \return a positive value when success otherwise a negative error number
+ *
+ * Example:
+\code
+ {
+ @func private_pcm_subdevice
+ }
+\endcode
+ */
+int snd_func_private_pcm_subdevice(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED,
+ snd_config_t *src, snd_config_t *private_data)
{
- char *res = NULL;
snd_pcm_info_t *info;
+ snd_config_t *n;
+ const char *id;
+ snd_pcm_t *pcm;
int err;
if (private_data == NULL)
return snd_config_copy(dst, src);
+ err = snd_config_test_id(private_data, "pcm_handle");
+ if (err) {
+ SNDERR("field pcm_handle not found");
+ return -EINVAL;
+ }
+ err = snd_config_get_pointer(private_data, (const void **)&pcm);
+ if (err < 0) {
+ SNDERR("field pcm_handle is not a pointer");
+ return err;
+ }
snd_pcm_info_alloca(&info);
- err = snd_pcm_info((snd_pcm_t *)private_data, info);
+ err = snd_pcm_info(pcm, info);
if (err < 0) {
SNDERR("snd_ctl_pcm_info error: %s", snd_strerror(err));
return err;
}
- res = strdup(snd_pcm_info_get_id(info));
- if (res == NULL)
- return -ENOMEM;
- err = snd_config_make_integer(dst, snd_config_get_id(src));
- if (err >= 0)
- err = snd_config_set_integer(*dst, snd_pcm_info_get_subdevice(info));
- free(res);
+ err = snd_config_get_id(src, &id);
+ if (err >= 0) {
+ err = snd_config_make_integer(dst, id);
+ if (err >= 0)
+ err = snd_config_set_integer(*dst, snd_pcm_info_get_subdevice(info));
+ }
return err;
}
+#ifndef DOC_HIDDEN
SND_DLSYM_BUILD_VERSION(snd_func_private_pcm_subdevice, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#endif
-int snd_func_refer(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data)
+/**
+ * \brief Copy the refered configuration node
+ * \param dst The destination node (result type is same as refered node)
+ * \param root The root source node (can be modified!!!)
+ * \param src The source node
+ * \param private_data The private_data node
+ * \return a positive value when success otherwise a negative error number
+ *
+ * Example:
+\code
+ {
+ @func refer
+ file "/etc/myconf.conf" # optional
+ name "id1.id2.id3"
+ }
+\endcode
+ */
+int snd_func_refer(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
+ snd_config_t *private_data)
{
snd_config_t *n;
const char *file = NULL, *name = NULL;
goto _end;
}
err = snd_config_load(root, input);
- if (err < 0) {
- snd_input_close(input);
+ snd_input_close(input);
+ if (err < 0)
goto _end;
- }
}
err = snd_config_search_definition(root, NULL, name, dst);
- if (err >= 0)
- err = snd_config_set_id(*dst, snd_config_get_id(src));
- else
+ if (err >= 0) {
+ const char *id;
+ err = snd_config_get_id(src, &id);
+ if (err >= 0)
+ err = snd_config_set_id(*dst, id);
+ } else
SNDERR("Unable to find definition '%s'", name);
_end:
return err;
}
+#ifndef DOC_HIDDEN
SND_DLSYM_BUILD_VERSION(snd_func_refer, SND_CONFIG_DLSYM_VERSION_EVALUATE);
+#endif
was_empty = list_empty(&ctl->async_handlers);
list_add_tail(&h->hlist, &ctl->async_handlers);
if (was_empty) {
- err = snd_ctl_async(ctl, getpid(), snd_async_signo);
+ err = snd_ctl_async(ctl, snd_async_get_signo(h), getpid());
if (err < 0) {
snd_async_del_handler(h);
return err;
snd_config_t *conf, *type_conf = NULL;
snd_config_iterator_t i, next;
const char *lib = NULL, *open_name = NULL;
+ const char *id;
int (*open_func)(snd_ctl_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL;
#ifndef PIC
extern void *snd_control_open_symbols(void);
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", snd_config_get_id(conf));
+ SNDERR("Invalid type for %s", id);
return err;
}
err = snd_config_search_definition(ctl_root, "ctl_type", str, &type_conf);
}
snd_config_for_each(i, next, type_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
int err;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "type") == 0)
struct hostent *h;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "type") == 0)
}
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "host") == 0) {
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- err = safe_strtol(snd_config_get_id(n), &idx);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
+ err = safe_strtol(id, &idx);
if (err < 0 || idx < 0 || (unsigned int) idx >= count) {
SNDERR("bad value index");
return -EINVAL;
return 0;
}
-static int add_elem(snd_sctl_t *h, snd_config_t *_conf, void *private_data)
+static int add_elem(snd_sctl_t *h, snd_config_t *_conf, snd_config_t *private_data)
{
snd_config_t *conf;
snd_config_iterator_t i, next;
return err;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "iface") == 0 || strcmp(id, "interface") == 0) {
* \param mode Build mode - SND_SCTL_xxxx
* \result zero if success, otherwise a negative error code
*/
-int snd_sctl_build(snd_sctl_t **sctl, snd_ctl_t *handle, snd_config_t *conf, void *private_data, int mode)
+int snd_sctl_build(snd_sctl_t **sctl, snd_ctl_t *handle, snd_config_t *conf, snd_config_t *private_data, int mode)
{
snd_sctl_t *h;
snd_config_iterator_t i, next;
* \param name name, similar to dlopen
* \param mode mode, similar to dlopen
* \return pointer to handle
+ *
+ * The extension is a special code for the static build of
+ * the alsa-lib library.
*/
void *snd_dlopen(const char *name, int mode)
{
* \brief Close the dynamic library, with ALSA extension
* \param handle handle, similar to dlclose
* \return zero if success, otherwise an error code
+ *
+ * The extension is a special code for the static build of
+ * the alsa-lib library.
*/
int snd_dlclose(void *handle)
{
if (handle == NULL)
return -EINVAL;
vname = alloca(1 + strlen(name) + strlen(version) + 1);
+ if (vname == NULL)
+ return -ENOMEM;
vname[0] = '_';
strcpy(vname + 1, name);
strcat(vname, version);
SNDERR("unable to verify version for symbol %s", name);
return res;
}
+
/**
* \brief Resolve the symbol, with ALSA extension
* \param handle handle, similar to dlsym
* \param name symbol name
* \param version symbol version
+ *
+ * This special version of dlsym function checks also
+ * the version of symbol. The version of a symbol should
+ * be defined using #SND_DLSYM_BUILD_VERSION macro.
*/
void *snd_dlsym(void *handle, const char *name, const char *version)
{
#ifndef PIC
if (handle == &snd_dlsym_start) {
- /* it's the funny part, we are looking for a symbol */
- /* in a static library */
+ /* it's the funny part: */
+ /* we are looking for a symbol in a static library */
struct snd_dlsym_link *link = snd_dlsym_start;
while (link) {
if (!strcmp(name, link->dlsym_name))
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_hwdep_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL;
#ifndef PIC
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", snd_config_get_id(conf));
+ SNDERR("Invalid type for %s", id);
return err;
}
err = snd_config_search_definition(hwdep_root, "hwdep_type", str, &type_conf);
}
snd_config_for_each(i, next, type_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
int err;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "type") == 0)
/**
* \file pcm/pcm.c
+ * \ingroup PCM
* \brief PCM Interface
* \author Jaroslav Kysela <perex@suse.cz>
* \author Abramo Bagnara <abramo@alsa-project.org>
* 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
*
*/
+/*! \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>
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, getpid());
+ err = snd_pcm_async(pcm, snd_async_signo(h), getpid());
if (err < 0) {
snd_async_del_handler(h);
return err;
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 *,
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", snd_config_get_id(conf));
+ SNDERR("Invalid type for %s", id);
return err;
}
err = snd_config_search_definition(pcm_root, "pcm_type", str, &type_conf);
}
snd_config_for_each(i, next, type_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
va_end(args);
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "pcm") == 0) {
snd_pcm_format_t sformat;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
snd_pcm_format_t sformat;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
snd_config_t *slave = NULL, *sconf;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
long fd = -1;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
{
int err;
char buf[256];
- const char *str;
+ const char *str, *id;
const char *lib = NULL, *install = NULL;
snd_config_t *type = NULL, *args = NULL;
snd_config_iterator_t i, next;
}
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "type") == 0) {
SNDERR("type is not defined");
return -EINVAL;
}
+ err = snd_config_get_id(type, &id);
+ if (err < 0) {
+ SNDERR("unable to get id");
+ return err;
+ }
err = snd_config_get_string(type, &str);
if (err < 0) {
- SNDERR("Invalid type for %s", snd_config_get_id(type));
+ SNDERR("Invalid type for %s", id);
return err;
}
err = snd_config_search_definition(root, "pcm_hook_type", str, &type);
}
snd_config_for_each(i, next, type) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
snd_config_t *hooks = NULL;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
char ctl_name[16];
snd_ctl_t *ctl;
snd_sctl_t *sctl;
+ snd_config_t *pcm_conf = NULL;
snd_pcm_hook_t *h_hw_params = NULL, *h_hw_free = NULL, *h_close = NULL;
assert(conf);
assert(snd_config_get_type(conf) == SND_CONFIG_TYPE_COMPOUND);
SNDERR("Cannot open CTL %s", ctl_name);
return err;
}
- err = snd_sctl_build(&sctl, ctl, conf, pcm, 0);
+ err = snd_config_make_pointer(&pcm_conf, "pcm_handle");
if (err < 0)
- return -ENOMEM;
+ goto _err;
+ snd_config_set_pointer(pcm_conf, pcm);
+ err = snd_sctl_build(&sctl, ctl, conf, pcm_conf, 0);
+ if (err < 0)
+ goto _err;
err = snd_pcm_hook_add(&h_hw_params, pcm, SND_PCM_HOOK_TYPE_HW_PARAMS,
snd_pcm_hook_ctl_elems_hw_params, sctl);
if (err < 0)
if (h_close)
snd_pcm_hook_remove(h_close);
snd_sctl_free(sctl);
+ if (pcm_conf)
+ snd_config_delete(pcm_conf);
return err;
}
int err;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "card") == 0) {
snd_pcm_format_t sformat;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
{
char buf[256];
snd_config_iterator_t i, next;
+ const char *id;
const char *lib = NULL, *open_name = NULL, *str = NULL;
snd_config_t *c, *type_conf;
int (*open_func)(snd_pcm_t *, const char *,
SNDERR("type is not defined");
goto _err;
}
+ err = snd_config_get_id(c, &id);
+ if (err < 0) {
+ SNDERR("unable to get id");
+ goto _err;
+ }
err = snd_config_get_string(c, &str);
if (err < 0) {
- SNDERR("Invalid type for %s", snd_config_get_id(c));
+ SNDERR("Invalid type for %s", id);
goto _err;
}
err = snd_config_search_definition(root, "pcm_scope_type", str, &type_conf);
if (err >= 0) {
snd_config_for_each(i, next, type_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
snd_config_t *scopes = NULL;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
return 0;
snd_config_for_each(i, next, scopes) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
- const char *str;
+ const char *id, *str;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_config_get_string(n, &str) >= 0) {
err = snd_config_search_definition(root, "pcm_scope", str, &n);
if (err < 0) {
snd_pcm_format_t sformat;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
unsigned int channels_count = 0;
snd_config_for_each(i, inext, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slaves") == 0) {
snd_config_for_each(i, inext, bindings) {
long cchannel;
snd_config_t *m = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(m);
+ const char *id;
+ if (snd_config_get_id(m, &id) < 0)
+ continue;
err = safe_strtol(id, &cchannel);
if (err < 0 || cchannel < 0) {
SNDERR("Invalid channel number: %s", id);
idx = 0;
snd_config_for_each(i, inext, slaves) {
snd_config_t *m = snd_config_iterator_entry(i);
+ const char *id;
int channels;
- slaves_id[idx] = snd_config_get_id(m);
+ if (snd_config_get_id(m, &id) < 0)
+ continue;
+ slaves_id[idx] = id;
err = snd_pcm_slave_conf(root, m, &slaves_conf[idx], 1,
SND_PCM_HW_PARAM_CHANNELS, SCONF_MANDATORY, &channels);
if (err < 0)
int slave = -1;
long val;
const char *str;
- const char *id = snd_config_get_id(m);
+ const char *id;
+ if (snd_config_get_id(m, &id) < 0)
+ continue;
err = safe_strtol(id, &cchannel);
if (err < 0 || cchannel < 0) {
SNDERR("Invalid channel number: %s", id);
}
snd_config_for_each(j, jnext, m) {
snd_config_t *n = snd_config_iterator_entry(j);
- id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "slave") == 0) {
goto _free;
}
if (slave < 0 || (unsigned int)slave >= slaves_count) {
- SNDERR("Invalid or missing sidx");
+ SNDERR("Invalid or missing sidx for channel %s", id);
err = -EINVAL;
goto _free;
}
if (schannel < 0 ||
(unsigned int) schannel >= slaves_channels[slave]) {
- SNDERR("Invalid or missing schannel");
+ SNDERR("Invalid or missing schannel for channel %s", id);
err = -EINVAL;
goto _free;
}
snd_config_iterator_t i, next;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
SNDERR("Unknown field %s", id);
int schannels = -1, srate = -1;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
int srate = -1;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
snd_config_t *in = snd_config_iterator_entry(i);
snd_config_iterator_t j, jnext;
long cchannel;
- err = safe_strtol(snd_config_get_id(in), &cchannel);
+ const char *id;
+ if (!snd_config_get_id(in, &id) < 0)
+ continue;
+ err = safe_strtol(id, &cchannel);
if (err < 0 ||
cchannel < 0 || (unsigned int) cchannel > tt_csize) {
- SNDERR("Invalid client channel: %s", snd_config_get_id(in));
+ SNDERR("Invalid client channel: %s", id);
return -EINVAL;
}
if (snd_config_get_type(in) != SND_CONFIG_TYPE_COMPOUND)
snd_config_t *jnode = snd_config_iterator_entry(j);
double value;
long schannel;
- const char *id = snd_config_get_id(jnode);
+ const char *id;
+ if (snd_config_get_id(jnode, &id) < 0)
+ continue;
err = safe_strtol(id, &schannel);
if (err < 0 ||
schannel < 0 || (unsigned int) schannel > tt_ssize ||
unsigned int cused, sused;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "slave") == 0) {
snd_config_for_each(i, next, bindings) {
long cchannel = -1;
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
err = safe_strtol(id, &cchannel);
if (err < 0 || cchannel < 0) {
SNDERR("Invalid client channel in binding: %s", id);
snd_config_for_each(i, next, bindings) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
long cchannel;
long schannel = -1;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
cchannel = atoi(id);
err = snd_config_get_integer(n, &schannel);
if (err < 0) {
struct hostent *h;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (snd_pcm_conf_generic_id(id))
continue;
if (strcmp(id, "server") == 0) {
}
snd_config_for_each(i, next, sconfig) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "host") == 0) {
snd_config_t *conf, *type_conf = NULL;
snd_config_iterator_t i, next;
snd_rawmidi_params_t params;
+ const char *id;
const char *lib = NULL, *open_name = NULL;
int (*open_func)(snd_rawmidi_t **, snd_rawmidi_t **,
const char *, snd_config_t *, snd_config_t *, int) = NULL;
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", snd_config_get_id(conf));
+ SNDERR("Invalid type for %s", id);
return err;
}
err = snd_config_search_definition(rawmidi_root, "rawmidi_type", str, &type_conf);
}
snd_config_for_each(i, next, type_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
int err;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "type") == 0)
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_seq_t **, const char *,
snd_config_t *, snd_config_t *,
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", snd_config_get_id(conf));
+ SNDERR("Invalid type for %s", id);
return err;
}
err = snd_config_search_definition(seq_root, "seq_type", str, &type_conf);
}
snd_config_for_each(i, next, type_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
snd_config_iterator_t i, next;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "type") == 0)
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_timer_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL;
#ifndef PIC
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", snd_config_get_id(conf));
+ SNDERR("Invalid type for %s", id);
return err;
}
err = snd_config_search_definition(timer_root, "timer_type", str, &type_conf);
}
snd_config_for_each(i, next, type_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
int err;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "type") == 0)
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_timer_query_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL;
#ifndef PIC
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", snd_config_get_id(conf));
+ SNDERR("Invalid type for %s", id);
return err;
}
err = snd_config_search_definition(timer_root, "timer_query_type", str, &type_conf);
}
snd_config_for_each(i, next, type_conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "lib") == 0) {
snd_config_iterator_t i, next;
snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i);
- const char *id = snd_config_get_id(n);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
if (strcmp(id, "comment") == 0)
continue;
if (strcmp(id, "type") == 0)