mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-02 09:01:48 -05:00
removed ordinary stuff
This commit is contained in:
parent
ff9fd33190
commit
41398ceb9c
7 changed files with 1 additions and 1882 deletions
|
|
@ -1,219 +0,0 @@
|
||||||
/**
|
|
||||||
* \file include/mixer_ordinary.h
|
|
||||||
* \brief Application interface library for the ALSA driver
|
|
||||||
* \author Jaroslav Kysela <perex@suse.cz>
|
|
||||||
* \date 2003
|
|
||||||
*
|
|
||||||
* Application interface library for the ALSA driver.
|
|
||||||
* See the \ref mixer_ordinary page for more details.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* This library is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2.1 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __ALSA_MIXER_SIMPLE_H
|
|
||||||
#define __ALSA_MIXER_SIMPLE_H
|
|
||||||
|
|
||||||
#include <alsa/asoundlib.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Abbreviations:
|
|
||||||
*
|
|
||||||
* FLVOL - Front Left Volume (0-1000)
|
|
||||||
* FCLVOL - Front Center Left Volume (0-1000)
|
|
||||||
* FCVOL - Front Center Volume (0-1000)
|
|
||||||
* FCRVOL - Front Center Right Volume (0-1000)
|
|
||||||
* FRVOL - Front Right Volume (0-1000)
|
|
||||||
* FSLVOL - Front Side Left Volume (0-1000)
|
|
||||||
* FSRVOL - Front Side Right Volume (0-1000)
|
|
||||||
* RSLVOL - Rear Side Left Volume (0-1000)
|
|
||||||
* RSRVOL - Rear Side Right Volume (0-1000)
|
|
||||||
* RLVOL - Rear Left Volume (0-1000)
|
|
||||||
* RCVOL - Rear Center Volume (0-1000)
|
|
||||||
* RRVOL - Rear Right Volume (0-1000)
|
|
||||||
* LFEVOL - Low Frequency Effects (Subwoofer) Volume (0-1000)
|
|
||||||
* OVRVOL - Overhead Volume (0-1000)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Ordinary Mixer I/O type */
|
|
||||||
enum sndo_mixer_io_type {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* playback section
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Master */
|
|
||||||
SNDO_MIO_MASTER_FLVOL = 0 * 0x40,
|
|
||||||
SNDO_MIO_MASTER_FCLVOL,
|
|
||||||
SNDO_MIO_MASTER_FCVOL,
|
|
||||||
SNDO_MIO_MASTER_FCRVOL,
|
|
||||||
SNDO_MIO_MASTER_FRVOL,
|
|
||||||
SNDO_MIO_MASTER_FSLVOL,
|
|
||||||
SNDO_MIO_MASTER_FSRVOL,
|
|
||||||
SNDO_MIO_MASTER_RSLVOL,
|
|
||||||
SNDO_MIO_MASTER_RSRVOL,
|
|
||||||
SNDO_MIO_MASTER_RLVOL,
|
|
||||||
SNDO_MIO_MASTER_RCVOL,
|
|
||||||
SNDO_MIO_MASTER_RRVOL,
|
|
||||||
SNDO_MIO_MASTER_LFEVOL,
|
|
||||||
SNDO_MIO_MASTER_OVRVOL,
|
|
||||||
|
|
||||||
/* PCM */
|
|
||||||
SNDO_MIO_PCM_FLVOL = 1 * 0x40,
|
|
||||||
SNDO_MIO_PCM_FCLVOL,
|
|
||||||
SNDO_MIO_PCM_FCVOL,
|
|
||||||
SNDO_MIO_PCM_FCRVOL,
|
|
||||||
SNDO_MIO_PCM_FRVOL,
|
|
||||||
SNDO_MIO_PCM_FSLVOL,
|
|
||||||
SNDO_MIO_PCM_FSRVOL,
|
|
||||||
SNDO_MIO_PCM_RSLVOL,
|
|
||||||
SNDO_MIO_PCM_RSRVOL,
|
|
||||||
SNDO_MIO_PCM_RLVOL,
|
|
||||||
SNDO_MIO_PCM_RCVOL,
|
|
||||||
SNDO_MIO_PCM_RRVOL,
|
|
||||||
SNDO_MIO_PCM_LFEVOL,
|
|
||||||
SNDO_MIO_PCM_OVRVOL,
|
|
||||||
|
|
||||||
/* LINE */
|
|
||||||
SNDO_MIO_LINE_FLVOL = 2 * 0x40,
|
|
||||||
SNDO_MIO_LINE_FCLVOL,
|
|
||||||
SNDO_MIO_LINE_FCVOL,
|
|
||||||
SNDO_MIO_LINE_FCRVOL,
|
|
||||||
SNDO_MIO_LINE_FRVOL,
|
|
||||||
SNDO_MIO_LINE_FSLVOL,
|
|
||||||
SNDO_MIO_LINE_FSRVOL,
|
|
||||||
SNDO_MIO_LINE_RSLVOL,
|
|
||||||
SNDO_MIO_LINE_RSRVOL,
|
|
||||||
SNDO_MIO_LINE_RLVOL,
|
|
||||||
SNDO_MIO_LINE_RCVOL,
|
|
||||||
SNDO_MIO_LINE_RRVOL,
|
|
||||||
SNDO_MIO_LINE_LFEVOL,
|
|
||||||
SNDO_MIO_LINE_OVRVOL,
|
|
||||||
|
|
||||||
/* MIC */
|
|
||||||
SNDO_MIO_MIC_FLVOL = 3 * 0x40,
|
|
||||||
SNDO_MIO_MIC_FCLVOL,
|
|
||||||
SNDO_MIO_MIC_FCVOL,
|
|
||||||
SNDO_MIO_MIC_FCRVOL,
|
|
||||||
SNDO_MIO_MIC_FRVOL,
|
|
||||||
SNDO_MIO_MIC_FSLVOL,
|
|
||||||
SNDO_MIO_MIC_FSRVOL,
|
|
||||||
SNDO_MIO_MIC_RSLVOL,
|
|
||||||
SNDO_MIO_MIC_RSRVOL,
|
|
||||||
SNDO_MIO_MIC_RLVOL,
|
|
||||||
SNDO_MIO_MIC_RCVOL,
|
|
||||||
SNDO_MIO_MIC_RRVOL,
|
|
||||||
SNDO_MIO_MIC_LFEVOL,
|
|
||||||
SNDO_MIO_MIC_OVRVOL,
|
|
||||||
|
|
||||||
/* CD */
|
|
||||||
SNDO_MIO_CD_FLVOL = 4 * 0x40,
|
|
||||||
SNDO_MIO_CD_FCLVOL,
|
|
||||||
SNDO_MIO_CD_FCVOL,
|
|
||||||
SNDO_MIO_CD_FCRVOL,
|
|
||||||
SNDO_MIO_CD_FRVOL,
|
|
||||||
SNDO_MIO_CD_FSLVOL,
|
|
||||||
SNDO_MIO_CD_FSRVOL,
|
|
||||||
SNDO_MIO_CD_RSLVOL,
|
|
||||||
SNDO_MIO_CD_RSRVOL,
|
|
||||||
SNDO_MIO_CD_RLVOL,
|
|
||||||
SNDO_MIO_CD_RCVOL,
|
|
||||||
SNDO_MIO_CD_RRVOL,
|
|
||||||
SNDO_MIO_CD_LFEVOL,
|
|
||||||
SNDO_MIO_CD_OVRVOL,
|
|
||||||
|
|
||||||
/* AUX */
|
|
||||||
SNDO_MIO_AUX_FLVOL = 5 * 0x40,
|
|
||||||
SNDO_MIO_AUX_FCLVOL,
|
|
||||||
SNDO_MIO_AUX_FCVOL,
|
|
||||||
SNDO_MIO_AUX_FCRVOL,
|
|
||||||
SNDO_MIO_AUX_FRVOL,
|
|
||||||
SNDO_MIO_AUX_FSLVOL,
|
|
||||||
SNDO_MIO_AUX_FSRVOL,
|
|
||||||
SNDO_MIO_AUX_RSLVOL,
|
|
||||||
SNDO_MIO_AUX_RSRVOL,
|
|
||||||
SNDO_MIO_AUX_RLVOL,
|
|
||||||
SNDO_MIO_AUX_RCVOL,
|
|
||||||
SNDO_MIO_AUX_RRVOL,
|
|
||||||
SNDO_MIO_AUX_LFEVOL,
|
|
||||||
SNDO_MIO_AUX_OVRVOL,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* capture section
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* capture gain */
|
|
||||||
SNDO_MIO_CGAIN_FL = 0x8000,
|
|
||||||
SNDO_MIO_CGAIN_FCL,
|
|
||||||
SNDO_MIO_CGAIN_FC,
|
|
||||||
SNDO_MIO_CGAIN_FCR,
|
|
||||||
SNDO_MIO_CGAIN_FR,
|
|
||||||
SNDO_MIO_CGAIN_FSL,
|
|
||||||
SNDO_MIO_CGAIN_FSR,
|
|
||||||
SNDO_MIO_CGAIN_RSL,
|
|
||||||
SNDO_MIO_CGAIN_RSR,
|
|
||||||
SNDO_MIO_CGAIN_RL,
|
|
||||||
SNDO_MIO_CGAIN_RC,
|
|
||||||
SNDO_MIO_CGAIN_RR,
|
|
||||||
SNDO_MIO_CGAIN_LFE,
|
|
||||||
SNDO_MIO_CGAIN_OVR,
|
|
||||||
|
|
||||||
/* capture source (0 = off, 1 = on) */
|
|
||||||
SNDO_MIO_CSOURCE_MIC = 0x8100,
|
|
||||||
SNDO_MIO_CSOURCE_LINE,
|
|
||||||
SNDO_MIO_CSOURCE_CD,
|
|
||||||
SNDO_MIO_CSOURCE_AUX,
|
|
||||||
SNDO_MIO_CSOURCE_MIX,
|
|
||||||
|
|
||||||
/* misc */
|
|
||||||
SNDO_MIO_STEREO = 0x8200, /* (0 = off, 1 = on) standard stereo source, might be converted to use all outputs */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct sndo_mixer sndo_mixer_t;
|
|
||||||
struct alisp_cfg;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \defgroup Mixer_ordinary Mixer Ordinary Interface
|
|
||||||
* See the \ref mixer_ordinary page for more details.
|
|
||||||
* \{
|
|
||||||
*/
|
|
||||||
|
|
||||||
int sndo_mixer_open(sndo_mixer_t **pmixer, const char *playback_name, const char *capture_name, struct alisp_cfg *lconf);
|
|
||||||
int sndo_mixer_open_pcm(sndo_mixer_t **pmixer, snd_pcm_t *playback_pcm, snd_pcm_t *capture_pcm, struct alisp_cfg *lconf);
|
|
||||||
int sndo_mixer_close(sndo_mixer_t *mixer);
|
|
||||||
int sndo_mixer_poll_descriptors_count(sndo_mixer_t *mixer);
|
|
||||||
int sndo_mixer_poll_descriptors(sndo_mixer_t *mixer, struct pollfd *pfds, unsigned int space);
|
|
||||||
int sndo_mixer_poll_descriptors_revents(sndo_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
|
|
||||||
int sndo_mixer_io_get_name(enum sndo_mixer_io_type type, char **name);
|
|
||||||
int sndo_mixer_io_get(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
|
|
||||||
int sndo_mixer_io_set(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
|
|
||||||
int sndo_mixer_io_try_set(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
|
|
||||||
int sndo_mixer_io_get_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
|
|
||||||
int sndo_mixer_io_set_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
|
|
||||||
int sndo_mixer_io_try_set_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
|
|
||||||
int sndo_mixer_io_change(sndo_mixer_t *mixer, enum sndo_mixer_io_type *changed, int changed_array_size);
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __ALSA_MIXER_SIMPLE_H */
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
/**
|
|
||||||
* \file include/pcm_ordinary.h
|
|
||||||
* \brief Application interface library for the ALSA driver
|
|
||||||
* \author Jaroslav Kysela <perex@suse.cz>
|
|
||||||
* \date 2003
|
|
||||||
*
|
|
||||||
* Application interface library for the ALSA driver.
|
|
||||||
* See the \ref pcm_ordinary page for more details.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* This library is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2.1 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __ALSA_PCM_ORDINARY_H
|
|
||||||
#define __ALSA_PCM_ORDINARY_H
|
|
||||||
|
|
||||||
#include <alsa/asoundlib.h>
|
|
||||||
|
|
||||||
/** Ordinary PCM latency type */
|
|
||||||
enum sndo_pcm_latency_type {
|
|
||||||
/** normal latency - for standard playback or capture
|
|
||||||
(estimated latency in one direction 350ms) (default) */
|
|
||||||
SNDO_PCM_LATENCY_NORMAL = 0,
|
|
||||||
/** medium latency - software phones etc.
|
|
||||||
(estimated latency in one direction maximally 50ms) */
|
|
||||||
SNDO_PCM_LATENCY_MEDIUM,
|
|
||||||
/** realtime latency - realtime applications (effect processors etc.)
|
|
||||||
(estimated latency in one direction 5ms) */
|
|
||||||
SNDO_PCM_LATENCY_REALTIME
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Ordinary PCM access type */
|
|
||||||
enum sndo_pcm_access_type {
|
|
||||||
/** interleaved access - channels are interleaved without any gaps among samples (default) */
|
|
||||||
SNDO_PCM_ACCESS_INTERLEAVED = 0,
|
|
||||||
/** noninterleaved access - channels are separate without any gaps among samples */
|
|
||||||
SNDO_PCM_ACCESS_NONINTERLEAVED
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Ordinary PCM xrun type */
|
|
||||||
enum sndo_pcm_xrun_type {
|
|
||||||
/** driver / library will ignore all xruns, the stream runs forever (default) */
|
|
||||||
SNDO_PCM_XRUN_IGNORE = 0,
|
|
||||||
/** driver / library stops the stream when an xrun occurs */
|
|
||||||
SNDO_PCM_XRUN_STOP
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct sndo_pcm sndo_pcm_t;
|
|
||||||
|
|
||||||
typedef int (sndo_pcm_engine_callback_t)(sndo_pcm_t *pcm);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \defgroup PCM_ordinary PCM Ordinary Interface
|
|
||||||
* See the \ref pcm_ordinary page for more details.
|
|
||||||
* \{
|
|
||||||
*/
|
|
||||||
|
|
||||||
int sndo_pcm_open(sndo_pcm_t **pcm, const char *playback_name, const char *capture_name, struct alisp_cfg *lconf);
|
|
||||||
int sndo_pcm_close(sndo_pcm_t *pcm);
|
|
||||||
int sndo_pcm_poll_descriptors_count(sndo_pcm_t *pcm);
|
|
||||||
int sndo_pcm_poll_descriptors(sndo_pcm_t *pcm, struct pollfd *pfds, unsigned int space);
|
|
||||||
int sndo_pcm_start(sndo_pcm_t *pcm);
|
|
||||||
int sndo_pcm_drop(sndo_pcm_t *pcm);
|
|
||||||
int sndo_pcm_drain(sndo_pcm_t *pcm);
|
|
||||||
int sndo_pcm_delay(sndo_pcm_t *pcm, snd_pcm_sframes_t *delayp);
|
|
||||||
int sndo_pcm_transfer_block(sndo_pcm_t *pcm, snd_pcm_uframes_t *tblock);
|
|
||||||
int sndo_pcm_resume(sndo_pcm_t *pcm);
|
|
||||||
int sndo_pcm_wait(sndo_pcm_t *pcm, int timeout);
|
|
||||||
snd_pcm_t *sndo_pcm_raw_playback(sndo_pcm_t *pcm);
|
|
||||||
snd_pcm_t *sndo_pcm_raw_capture(sndo_pcm_t *pcm);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \defgroup PCM_ordinary_params Parameters Functions
|
|
||||||
* \ingroup PCM_ordinary
|
|
||||||
* See the \ref pcm_ordinary page for more details.
|
|
||||||
* \{
|
|
||||||
*/
|
|
||||||
|
|
||||||
int sndo_pcm_param_reset(sndo_pcm_t *pcm);
|
|
||||||
int sndo_pcm_param_access(sndo_pcm_t *pcm, enum sndo_pcm_access_type access);
|
|
||||||
int sndo_pcm_param_rate(sndo_pcm_t *pcm, unsigned int rate, unsigned int *used_rate);
|
|
||||||
int sndo_pcm_param_channels(sndo_pcm_t *pcm, unsigned int channels);
|
|
||||||
int sndo_pcm_param_format(sndo_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_subformat_t subformat);
|
|
||||||
int sndo_pcm_param_latency(sndo_pcm_t *pcm, enum sndo_pcm_latency_type latency, snd_pcm_uframes_t *used_latency);
|
|
||||||
int sndo_pcm_param_xrun(sndo_pcm_t *pcm, enum sndo_pcm_xrun_type xrun);
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \defgroup PCM_ordinary_access Ring Buffer I/O Functions
|
|
||||||
* \ingroup PCM_ordinary
|
|
||||||
* See the \ref pcm_ordinary page for more details.
|
|
||||||
* \{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* playback */
|
|
||||||
int sndo_pcm_pio_ibegin(sndo_pcm_t *pcm, void **ring_buffer, snd_pcm_uframes_t *frames);
|
|
||||||
snd_pcm_sframes_t sndo_pcm_pio_iend(sndo_pcm_t *pcm, snd_pcm_uframes_t frames);
|
|
||||||
int sndo_pcm_pio_nbegin(sndo_pcm_t *pcm, void ***ring_buffer, snd_pcm_uframes_t *frames);
|
|
||||||
snd_pcm_sframes_t sndo_pcm_pio_nend(sndo_pcm_t *pcm, snd_pcm_uframes_t frames);
|
|
||||||
/* capture */
|
|
||||||
int sndo_pcm_cio_ibegin(sndo_pcm_t *pcm, void **ring_buffer, snd_pcm_uframes_t *frames);
|
|
||||||
snd_pcm_sframes_t sndo_pcm_cio_iend(sndo_pcm_t *pcm, snd_pcm_uframes_t frames);
|
|
||||||
int sndo_pcm_cio_nbegin(sndo_pcm_t *pcm, void ***ring_buffer, snd_pcm_uframes_t *frames);
|
|
||||||
snd_pcm_sframes_t sndo_pcm_cio_nend(sndo_pcm_t *pcm, snd_pcm_uframes_t frames);
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \defgroup PCM_ordinary_engine Callback like engine
|
|
||||||
* \ingroup PCM_ordinary
|
|
||||||
* See the \ref pcm_ordinary page for more details.
|
|
||||||
* \{
|
|
||||||
*/
|
|
||||||
|
|
||||||
int sndo_pcm_set_private_data(sndo_pcm_t *pcm, void *private_data);
|
|
||||||
int sndo_pcm_get_private_data(sndo_pcm_t *pcm, void **private_data);
|
|
||||||
int sndo_pcm_engine(sndo_pcm_t *pcm,
|
|
||||||
sndo_pcm_engine_callback_t *playback,
|
|
||||||
sndo_pcm_engine_callback_t *capture);
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __ALSA_PCM_ORDINARY_H */
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
SUBDIRS=control mixer ordinary_mixer pcm ordinary_pcm rawmidi timer hwdep seq instr compat conf alisp
|
SUBDIRS=control mixer pcm rawmidi timer hwdep seq instr compat conf alisp
|
||||||
EXTRA_DIST=Versions
|
EXTRA_DIST=Versions
|
||||||
COMPATNUM=@LIBTOOL_VERSION_INFO@
|
COMPATNUM=@LIBTOOL_VERSION_INFO@
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
#SUBDIRS =
|
|
||||||
#DIST_SUBDIRS =
|
|
||||||
|
|
||||||
EXTRA_LTLIBRARIES = libordinarymixer.la
|
|
||||||
|
|
||||||
libordinarymixer_la_SOURCES = ordinary_mixer.c
|
|
||||||
#noinst_HEADERS =
|
|
||||||
|
|
||||||
alsadir = $(datadir)/alsa
|
|
||||||
|
|
||||||
all: libordinarymixer.la
|
|
||||||
|
|
||||||
INCLUDES=-I$(top_srcdir)/include
|
|
||||||
|
|
@ -1,565 +0,0 @@
|
||||||
/**
|
|
||||||
* \file ordinary_mixer/ordinary_mixer.c
|
|
||||||
* \ingroup Mixer_ordinary
|
|
||||||
* \brief Ordinary mixer interface
|
|
||||||
* \author Jaroslav Kysela <perex@suse.cz>
|
|
||||||
* \date 2003,2004
|
|
||||||
*
|
|
||||||
* Ordinary mixer interface is a high level abtraction for soundcard's
|
|
||||||
* mixing.
|
|
||||||
*
|
|
||||||
* See the \ref Mixer_ordinary page for more details.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Ordinary Mixer Interface - main file
|
|
||||||
* Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2.1 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! \page Mixer_ordinary Ordinary mixer interface
|
|
||||||
|
|
||||||
<P>Write something here</P>
|
|
||||||
|
|
||||||
\section Mixer_ordinary_overview
|
|
||||||
|
|
||||||
Write something here
|
|
||||||
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* \example ../test/ordinary_mixer.c
|
|
||||||
* \anchor example_ordinary_mixer
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/poll.h>
|
|
||||||
#include <sys/shm.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include "local.h"
|
|
||||||
#include "alisp.h"
|
|
||||||
#include "mixer_ordinary.h"
|
|
||||||
|
|
||||||
struct sndo_mixer {
|
|
||||||
struct alisp_cfg *cfg;
|
|
||||||
struct alisp_instance *alisp;
|
|
||||||
int hctl_count;
|
|
||||||
snd_hctl_t **hctl;
|
|
||||||
int _free_cfg;
|
|
||||||
};
|
|
||||||
|
|
||||||
int sndo_mixer_open1(sndo_mixer_t **pmixer,
|
|
||||||
const char *lisp_fcn,
|
|
||||||
const char *lisp_fmt,
|
|
||||||
const void *parg,
|
|
||||||
const void *carg,
|
|
||||||
struct alisp_cfg *lconf)
|
|
||||||
{
|
|
||||||
struct alisp_cfg *cfg = lconf;
|
|
||||||
struct alisp_instance *alisp;
|
|
||||||
struct alisp_seq_iterator *iterator;
|
|
||||||
sndo_mixer_t *mixer;
|
|
||||||
int err, count;
|
|
||||||
long val;
|
|
||||||
|
|
||||||
*pmixer = NULL;
|
|
||||||
if (cfg == NULL) {
|
|
||||||
char *file;
|
|
||||||
snd_input_t *input;
|
|
||||||
file = getenv("ALSA_ORDINARY_MIXER");
|
|
||||||
if (!file)
|
|
||||||
file = DATADIR "/alsa/sndo-mixer.alisp";
|
|
||||||
if ((err = snd_input_stdio_open(&input, file, "r")) < 0) {
|
|
||||||
SNDERR("unable to open alisp file '%s'", file);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
cfg = alsa_lisp_default_cfg(input);
|
|
||||||
if (cfg == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
cfg->warning = 1;
|
|
||||||
#if 0
|
|
||||||
cfg->debug = 1;
|
|
||||||
cfg->verbose = 1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
err = alsa_lisp(cfg, &alisp);
|
|
||||||
if (err < 0)
|
|
||||||
goto __error;
|
|
||||||
err = alsa_lisp_function(alisp, &iterator, lisp_fcn, lisp_fmt, parg, carg);
|
|
||||||
if (err < 0) {
|
|
||||||
alsa_lisp_free(alisp);
|
|
||||||
goto __error;
|
|
||||||
}
|
|
||||||
err = alsa_lisp_seq_integer(iterator, &val);
|
|
||||||
if (err == 0 && val < 0)
|
|
||||||
err = val;
|
|
||||||
alsa_lisp_result_free(alisp, iterator);
|
|
||||||
if (err < 0) {
|
|
||||||
alsa_lisp_free(alisp);
|
|
||||||
goto __error;
|
|
||||||
}
|
|
||||||
count = 0;
|
|
||||||
if (alsa_lisp_seq_first(alisp, "hctls", &iterator) == 0) {
|
|
||||||
count = alsa_lisp_seq_count(iterator);
|
|
||||||
if (count < 0)
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
mixer = malloc(sizeof(sndo_mixer_t) + count * sizeof(snd_hctl_t *));
|
|
||||||
if (mixer == NULL) {
|
|
||||||
alsa_lisp_free(alisp);
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto __error;
|
|
||||||
}
|
|
||||||
memset(mixer, 0, sizeof(sndo_mixer_t));
|
|
||||||
if (count > 0) {
|
|
||||||
mixer->hctl = (snd_hctl_t **)(mixer + 1);
|
|
||||||
do {
|
|
||||||
if (alsa_lisp_seq_pointer(iterator, "hctl", (void **)&mixer->hctl[mixer->hctl_count++]))
|
|
||||||
break;
|
|
||||||
} while (mixer->hctl_count < count && alsa_lisp_seq_next(&iterator) == 0);
|
|
||||||
if (mixer->hctl_count < count) {
|
|
||||||
mixer->hctl = NULL;
|
|
||||||
mixer->hctl_count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mixer->alisp = alisp;
|
|
||||||
mixer->cfg = cfg;
|
|
||||||
mixer->_free_cfg = cfg != lconf;
|
|
||||||
*pmixer = mixer;
|
|
||||||
return 0;
|
|
||||||
__error:
|
|
||||||
if (cfg != lconf)
|
|
||||||
alsa_lisp_default_cfg_free(cfg);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Opens a ordinary mixer instance
|
|
||||||
* \param pmixer Returned ordinary mixer handle
|
|
||||||
* \param playback_name name for playback HCTL communication
|
|
||||||
* \param capture_name name for capture HCTL communication
|
|
||||||
* \param lconf Local configuration (might be NULL - use global configuration)
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_mixer_open(sndo_mixer_t **pmixer,
|
|
||||||
const char *playback_name,
|
|
||||||
const char *capture_name,
|
|
||||||
struct alisp_cfg *lconf)
|
|
||||||
{
|
|
||||||
return sndo_mixer_open1(pmixer, "sndo_mixer_open", "%s%s", playback_name, capture_name, lconf);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Opens a ordinary mixer instance
|
|
||||||
* \param pmixer Returned ordinary mixer handle
|
|
||||||
* \param playback_pcm handle of the playback PCM
|
|
||||||
* \param capture_pcm handle of the capture PCM
|
|
||||||
* \param lconf Local configuration (might be NULL - use global configuration)
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_mixer_open_pcm(sndo_mixer_t **pmixer,
|
|
||||||
snd_pcm_t *playback_pcm,
|
|
||||||
snd_pcm_t *capture_pcm,
|
|
||||||
struct alisp_cfg *lconf)
|
|
||||||
{
|
|
||||||
return sndo_mixer_open1(pmixer, "sndo_mixer_open_pcm", "%ppcm%ppcm", playback_pcm, capture_pcm, lconf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Closes a ordinary mixer instance
|
|
||||||
* \param mixer Ordinary mixer handle to close
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_mixer_close(sndo_mixer_t *mixer)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
|
|
||||||
res = alsa_lisp_function(mixer->alisp, NULL, "sndo_mixer_close", "n");
|
|
||||||
alsa_lisp_free(mixer->alisp);
|
|
||||||
if (mixer->_free_cfg)
|
|
||||||
alsa_lisp_default_cfg_free(mixer->cfg);
|
|
||||||
free(mixer);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief get count of poll descriptors for ordinary mixer handle
|
|
||||||
* \param mixer ordinary mixer handle
|
|
||||||
* \return count of poll descriptors
|
|
||||||
*/
|
|
||||||
int sndo_mixer_poll_descriptors_count(sndo_mixer_t *mixer)
|
|
||||||
{
|
|
||||||
int idx, err, res = -EIO;
|
|
||||||
|
|
||||||
if (mixer->hctl_count > 0) {
|
|
||||||
for (idx = 0; idx < mixer->hctl_count; idx++) {
|
|
||||||
err = snd_hctl_poll_descriptors_count(mixer->hctl[idx]);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
res += err;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
struct alisp_seq_iterator *result;
|
|
||||||
long val;
|
|
||||||
err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_poll_descriptors_count", "n");
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = alsa_lisp_seq_integer(result, &val);
|
|
||||||
return err < 0 ? err : val;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief get poll descriptors
|
|
||||||
* \param mixer ordinary mixer handle
|
|
||||||
* \param pfds array of poll descriptors
|
|
||||||
* \param space space in the poll descriptor array
|
|
||||||
* \return count of filled descriptors
|
|
||||||
*/
|
|
||||||
int sndo_mixer_poll_descriptors(sndo_mixer_t *mixer, struct pollfd *pfds, unsigned int space)
|
|
||||||
{
|
|
||||||
int err, idx, res;
|
|
||||||
|
|
||||||
if (mixer->hctl_count > 0) {
|
|
||||||
for (idx = res = 0; idx < mixer->hctl_count && space > 0; idx++) {
|
|
||||||
err = snd_hctl_poll_descriptors(mixer->hctl[idx], pfds, space);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
res += err;
|
|
||||||
space -= err;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
} else {
|
|
||||||
struct alisp_seq_iterator *result;
|
|
||||||
long val;
|
|
||||||
err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_poll_descriptors", "%i", space);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
assert(0); /* FIXME: pass pfds to application */
|
|
||||||
err = alsa_lisp_seq_integer(result, &val);
|
|
||||||
return err < 0 ? err : val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief get returned events from poll descriptors
|
|
||||||
* \param mixer ordinary mixer handle
|
|
||||||
* \param pfds array of poll descriptors
|
|
||||||
* \param nfds count of poll descriptors
|
|
||||||
* \param revents returned events
|
|
||||||
* \return zero if success, otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_mixer_poll_descriptors_revents(sndo_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
|
|
||||||
{
|
|
||||||
int err, idx, count, res;
|
|
||||||
|
|
||||||
if (mixer->hctl_count > 0) {
|
|
||||||
for (idx = res = 0; idx < mixer->hctl_count && nfds > 0; idx++) {
|
|
||||||
err = snd_hctl_poll_descriptors_count(mixer->hctl[idx]);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
count = err;
|
|
||||||
if (nfds < (unsigned int)err)
|
|
||||||
return -EINVAL;
|
|
||||||
err = snd_hctl_poll_descriptors_revents(mixer->hctl[idx], pfds, count, revents);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (err != count)
|
|
||||||
return -EINVAL;
|
|
||||||
pfds += count;
|
|
||||||
nfds -= err;
|
|
||||||
revents += count;
|
|
||||||
res += count;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
} else {
|
|
||||||
struct alisp_seq_iterator *result;
|
|
||||||
long val, tmp;
|
|
||||||
|
|
||||||
assert(0); /* FIXME: pass pfds to alisp too */
|
|
||||||
err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_poll_descriptors_revents", "%i", nfds);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = alsa_lisp_seq_integer(result, &val);
|
|
||||||
if (err >= 0 && alsa_lisp_seq_count(result) > 1) {
|
|
||||||
alsa_lisp_seq_next(&result);
|
|
||||||
err = alsa_lisp_seq_integer(result, &tmp);
|
|
||||||
*revents = tmp;
|
|
||||||
} else {
|
|
||||||
*revents = 0;
|
|
||||||
}
|
|
||||||
return err < 0 ? err : val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define IOLINES 6
|
|
||||||
|
|
||||||
static const char *name_table1[] = {
|
|
||||||
"Master",
|
|
||||||
"PCM",
|
|
||||||
"Line",
|
|
||||||
"Mic"
|
|
||||||
"CD",
|
|
||||||
"AUX"
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SPEAKERS 14
|
|
||||||
|
|
||||||
static const char *name_table2[] = {
|
|
||||||
"Front Left",
|
|
||||||
"Front Center Left",
|
|
||||||
"Front Center",
|
|
||||||
"Front Center Right",
|
|
||||||
"Front Right",
|
|
||||||
"Front Side Left",
|
|
||||||
"Front Side Right",
|
|
||||||
"Rear Side Left",
|
|
||||||
"Rear Side Right",
|
|
||||||
"Rear Left",
|
|
||||||
"Rear Center",
|
|
||||||
"Rear Right",
|
|
||||||
"LFE (Subwoofer)",
|
|
||||||
"Overhead"
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CSOURCES 5
|
|
||||||
|
|
||||||
static const char *name_table3[] = {
|
|
||||||
"Mic",
|
|
||||||
"Line",
|
|
||||||
"CD",
|
|
||||||
"AUX",
|
|
||||||
"Mix",
|
|
||||||
};
|
|
||||||
|
|
||||||
static int compose_string(char **result, const char *s1, const char *s2, const char *s3, const char *s4)
|
|
||||||
{
|
|
||||||
int len = strlen(s1) + strlen(s2) + strlen(s3) + strlen(s4);
|
|
||||||
*result = malloc(len + 1);
|
|
||||||
if (*result == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
strcpy(*result, s1);
|
|
||||||
strcat(*result, s2);
|
|
||||||
strcat(*result, s3);
|
|
||||||
strcat(*result, s4);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief get ordinary mixer io control value
|
|
||||||
* \param mixer ordinary mixer handle
|
|
||||||
* \param type io type
|
|
||||||
* \param val returned value
|
|
||||||
* \return zero if success, otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_mixer_io_get_name(enum sndo_mixer_io_type type, char **name)
|
|
||||||
{
|
|
||||||
if (type < IOLINES * 0x40) {
|
|
||||||
int tmp = type / 0x40;
|
|
||||||
type %= 0x40;
|
|
||||||
if (type < SPEAKERS)
|
|
||||||
return compose_string(name, name_table1[tmp], " ", name_table2[type], " Volume");
|
|
||||||
} else if (type >= SNDO_MIO_CGAIN_FL && type < SNDO_MIO_CGAIN_FL + SPEAKERS) {
|
|
||||||
return compose_string(name, "Capture Gain ", name_table2[type - SNDO_MIO_CGAIN_FL], "", "");
|
|
||||||
} else if (type >= SNDO_MIO_CSOURCE_MIC && type < SNDO_MIO_CSOURCE_MIC + CSOURCES) {
|
|
||||||
return compose_string(name, "Capture Source ", name_table3[type - SNDO_MIO_CSOURCE_MIC], "", "");
|
|
||||||
}
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief get ordinary mixer io control value
|
|
||||||
* \param mixer ordinary mixer handle
|
|
||||||
* \param type io type
|
|
||||||
* \param val returned value
|
|
||||||
* \return zero if success, otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_mixer_io_get(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
|
|
||||||
{
|
|
||||||
struct alisp_seq_iterator *result;
|
|
||||||
long val1;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_set", "%i", type);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = alsa_lisp_seq_integer(result, &val1);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
*val = val1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief set ordinary mixer io control value
|
|
||||||
* \param mixer ordinary mixer handle
|
|
||||||
* \param type io type
|
|
||||||
* \param val desired value
|
|
||||||
* \return zero if success, otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_mixer_io_set(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
|
|
||||||
{
|
|
||||||
struct alisp_seq_iterator *result;
|
|
||||||
long val1;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_set", "%i%i", type, *val);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = alsa_lisp_seq_integer(result, &val1);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
*val = val1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief try to set ordinary mixer io control value
|
|
||||||
* \param mixer ordinary mixer handle
|
|
||||||
* \param type io type
|
|
||||||
* \param val desired value
|
|
||||||
* \return zero if success, otherwise a negative error code
|
|
||||||
*
|
|
||||||
* This function does not update the value.
|
|
||||||
* It only returns the real value which will be set.
|
|
||||||
*/
|
|
||||||
int sndo_mixer_io_try_set(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
|
|
||||||
{
|
|
||||||
struct alisp_seq_iterator *result;
|
|
||||||
long val1;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_try_set", "%i%i", type, *val);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = alsa_lisp_seq_integer(result, &val1);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
*val = val1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief get ordinary mixer io control value in dB (decibel units)
|
|
||||||
* \param mixer ordinary mixer handle
|
|
||||||
* \param type io type
|
|
||||||
* \param val returned value in dB
|
|
||||||
* \return zero if success, otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_mixer_io_get_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
|
|
||||||
{
|
|
||||||
struct alisp_seq_iterator *result;
|
|
||||||
long val1;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_set_dB", "%i", type);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = alsa_lisp_seq_integer(result, &val1);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
*val = val1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief set ordinary mixer io control value in dB (decibel units)
|
|
||||||
* \param mixer ordinary mixer handle
|
|
||||||
* \param type io type
|
|
||||||
* \param val desired value in dB
|
|
||||||
* \return zero if success, otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_mixer_io_set_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
|
|
||||||
{
|
|
||||||
struct alisp_seq_iterator *result;
|
|
||||||
long val1;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_set", "%i%i", type, *val);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = alsa_lisp_seq_integer(result, &val1);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
*val = val1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief try to set ordinary mixer io control value in dB (decibel units)
|
|
||||||
* \param mixer ordinary mixer handle
|
|
||||||
* \param type io type
|
|
||||||
* \param val desired and returned value in dB
|
|
||||||
* \return zero if success, otherwise a negative error code
|
|
||||||
*
|
|
||||||
* This function does not update the value.
|
|
||||||
* It only returns the real value which will be set.
|
|
||||||
*/
|
|
||||||
int sndo_mixer_io_try_set_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
|
|
||||||
{
|
|
||||||
struct alisp_seq_iterator *result;
|
|
||||||
long val1;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_try_set", "%i%i", type, *val);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = alsa_lisp_seq_integer(result, &val1);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
*val = val1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief get ordinary mixer io control change notification
|
|
||||||
* \param mixer ordinary mixer handle
|
|
||||||
* \param changed list of changed io types
|
|
||||||
* \param changed_array_size size of list of changed io types
|
|
||||||
* \return zero if success, otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_mixer_io_change(sndo_mixer_t *mixer, enum sndo_mixer_io_type *changed, int changed_array_size)
|
|
||||||
{
|
|
||||||
struct alisp_seq_iterator *result;
|
|
||||||
long val1;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_change", "%i", changed_array_size);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = alsa_lisp_seq_integer(result, &val1);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (val1 < 0)
|
|
||||||
return val1;
|
|
||||||
while (changed_array_size-- > 0) {
|
|
||||||
*changed = val1;
|
|
||||||
if (!alsa_lisp_seq_next(&result))
|
|
||||||
break;
|
|
||||||
err = alsa_lisp_seq_integer(result, &val1);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
#SUBDIRS =
|
|
||||||
#DIST_SUBDIRS =
|
|
||||||
|
|
||||||
EXTRA_LTLIBRARIES = libordinarypcm.la
|
|
||||||
|
|
||||||
libordinarypcm_la_SOURCES = ordinary_pcm.c
|
|
||||||
#noinst_HEADERS =
|
|
||||||
|
|
||||||
alsadir = $(datadir)/alsa
|
|
||||||
|
|
||||||
all: libordinarypcm.la
|
|
||||||
|
|
||||||
INCLUDES=-I$(top_srcdir)/include
|
|
||||||
|
|
@ -1,926 +0,0 @@
|
||||||
/**
|
|
||||||
* \file ordinary_pcm/ordinary_pcm.c
|
|
||||||
* \ingroup PCM_ordinary
|
|
||||||
* \brief Ordinary PCM interface
|
|
||||||
* \author Jaroslav Kysela <perex@suse.cz>
|
|
||||||
* \date 2003,2004
|
|
||||||
*
|
|
||||||
* Ordinary PCM interface is a high level abtraction for
|
|
||||||
* digital audio streaming.
|
|
||||||
*
|
|
||||||
* See the \ref PCM_ordinary page for more details.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Ordinary PCM Interface - main file
|
|
||||||
* Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2.1 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! \page PCM_ordinary Ordinary PCM interface
|
|
||||||
|
|
||||||
<P>Write something here</P>
|
|
||||||
|
|
||||||
\section PCM_ordinary_overview
|
|
||||||
|
|
||||||
Write something here
|
|
||||||
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* \example ../test/ordinary_pcm.c
|
|
||||||
* \anchor example_ordinary_pcm
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/poll.h>
|
|
||||||
#include <sys/shm.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include "asoundlib.h"
|
|
||||||
#include "alisp.h"
|
|
||||||
#include "pcm_ordinary.h"
|
|
||||||
|
|
||||||
struct sndo_pcm {
|
|
||||||
snd_pcm_t *playback;
|
|
||||||
snd_pcm_t *capture;
|
|
||||||
snd_pcm_hw_params_t *p_hw_params;
|
|
||||||
snd_pcm_hw_params_t *c_hw_params;
|
|
||||||
snd_pcm_sw_params_t *p_sw_params;
|
|
||||||
snd_pcm_sw_params_t *c_sw_params;
|
|
||||||
snd_pcm_t *master;
|
|
||||||
unsigned int channels;
|
|
||||||
unsigned int samplebytes;
|
|
||||||
snd_pcm_uframes_t p_offset;
|
|
||||||
snd_pcm_uframes_t c_offset;
|
|
||||||
snd_pcm_uframes_t p_period_size;
|
|
||||||
snd_pcm_uframes_t c_period_size;
|
|
||||||
snd_pcm_uframes_t transfer_block;
|
|
||||||
snd_pcm_uframes_t ring_size;
|
|
||||||
enum sndo_pcm_latency_type latency;
|
|
||||||
enum sndo_pcm_xrun_type xrun;
|
|
||||||
int setting_up;
|
|
||||||
int initialized;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int sndo_pcm_setup(sndo_pcm_t *pcm);
|
|
||||||
static int sndo_pcm_initialize(sndo_pcm_t *pcm);
|
|
||||||
|
|
||||||
static inline int sndo_pcm_check_setup(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
if (!pcm->initialized)
|
|
||||||
return sndo_pcm_initialize(pcm);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Opens a ordinary pcm instance
|
|
||||||
* \param ppcm Returned ordinary pcm handle
|
|
||||||
* \param playback_name ASCII identifier of the ordinary pcm handle (playback)
|
|
||||||
* \param capture_name ASCII identifier of the ordinary pcm handle (capture)
|
|
||||||
* \param lconf Local configuration (might be NULL - use global configuration)
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_open(sndo_pcm_t **ppcm,
|
|
||||||
const char *playback_name,
|
|
||||||
const char *capture_name,
|
|
||||||
struct alisp_cfg *lconf)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
sndo_pcm_t *pcm;
|
|
||||||
|
|
||||||
assert(ppcm);
|
|
||||||
assert(playback_name || capture_name);
|
|
||||||
*ppcm = NULL;
|
|
||||||
pcm = calloc(1, sizeof(sndo_pcm_t));
|
|
||||||
if (pcm == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
if (playback_name) {
|
|
||||||
err = snd_pcm_hw_params_malloc(&pcm->p_hw_params);
|
|
||||||
if (err < 0)
|
|
||||||
goto __end;
|
|
||||||
err = snd_pcm_sw_params_malloc(&pcm->p_sw_params);
|
|
||||||
}
|
|
||||||
if (capture_name) {
|
|
||||||
err = snd_pcm_hw_params_malloc(&pcm->c_hw_params);
|
|
||||||
if (err < 0)
|
|
||||||
goto __end;
|
|
||||||
err = snd_pcm_sw_params_malloc(&pcm->p_sw_params);
|
|
||||||
}
|
|
||||||
if (err < 0)
|
|
||||||
goto __end;
|
|
||||||
if (lconf) {
|
|
||||||
if (playback_name) {
|
|
||||||
err = snd_pcm_open_lconf(&pcm->playback, playback_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
goto __end;
|
|
||||||
}
|
|
||||||
if (capture_name) {
|
|
||||||
err = snd_pcm_open_lconf(&pcm->capture, playback_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
goto __end;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (playback_name) {
|
|
||||||
err = snd_pcm_open(&pcm->playback, playback_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
|
||||||
if (err < 0)
|
|
||||||
goto __end;
|
|
||||||
}
|
|
||||||
if (capture_name) {
|
|
||||||
err = snd_pcm_open(&pcm->capture, playback_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
|
|
||||||
if (err < 0)
|
|
||||||
goto __end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pcm->playback && pcm->capture) {
|
|
||||||
err = snd_pcm_link(pcm->playback, pcm->capture);
|
|
||||||
if (err < 0)
|
|
||||||
goto __end;
|
|
||||||
pcm->master = pcm->playback;
|
|
||||||
}
|
|
||||||
__end:
|
|
||||||
if (err < 0)
|
|
||||||
sndo_pcm_close(pcm);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Closes a ordinary pcm instance
|
|
||||||
* \param pcm Ordinary pcm handle to close
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_close(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (pcm->playback)
|
|
||||||
err = snd_pcm_close(pcm->playback);
|
|
||||||
if (pcm->capture)
|
|
||||||
err = snd_pcm_close(pcm->capture);
|
|
||||||
if (pcm->p_hw_params)
|
|
||||||
snd_pcm_hw_params_free(pcm->p_hw_params);
|
|
||||||
if (pcm->p_sw_params)
|
|
||||||
snd_pcm_sw_params_free(pcm->p_sw_params);
|
|
||||||
if (pcm->c_hw_params)
|
|
||||||
snd_pcm_hw_params_free(pcm->c_hw_params);
|
|
||||||
if (pcm->c_sw_params)
|
|
||||||
snd_pcm_sw_params_free(pcm->c_sw_params);
|
|
||||||
free(pcm);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief get count of poll descriptors for ordinary pcm handle
|
|
||||||
* \param pcm ordinary pcm handle
|
|
||||||
* \return count of poll descriptors
|
|
||||||
*/
|
|
||||||
int sndo_pcm_poll_descriptors_count(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
int err, res = 0;
|
|
||||||
|
|
||||||
err = snd_pcm_poll_descriptors_count(pcm->playback);
|
|
||||||
if (err > 0)
|
|
||||||
res += err;
|
|
||||||
err = snd_pcm_poll_descriptors_count(pcm->capture);
|
|
||||||
if (err > 0)
|
|
||||||
res += err;
|
|
||||||
return err < 0 ? err : res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief get poll descriptors
|
|
||||||
* \param pcm ordinary pcm handle
|
|
||||||
* \param pfds array of poll descriptors
|
|
||||||
* \param space space in the poll descriptor array
|
|
||||||
* \return count of filled descriptors
|
|
||||||
*/
|
|
||||||
int sndo_pcm_poll_descriptors(sndo_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
|
|
||||||
{
|
|
||||||
int playback, err, res = 0;
|
|
||||||
|
|
||||||
playback = snd_pcm_poll_descriptors_count(pcm->playback);
|
|
||||||
if (playback < 0)
|
|
||||||
return playback;
|
|
||||||
err = snd_pcm_poll_descriptors(pcm->playback, pfds, (unsigned)playback < space ? (unsigned)playback : space);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
res += err;
|
|
||||||
if ((unsigned)res < space) {
|
|
||||||
err = snd_pcm_poll_descriptors(pcm->capture, pfds + res, space - res);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
res += err;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief get returned events from poll descriptors
|
|
||||||
* \param pcm ordinary pcm handle
|
|
||||||
* \param pfds array of poll descriptors
|
|
||||||
* \param nfds count of poll descriptors
|
|
||||||
* \param revents returned events
|
|
||||||
* \return zero if success, otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_poll_descriptors_revents(sndo_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
|
|
||||||
{
|
|
||||||
int playback, err;
|
|
||||||
unsigned short _revents;
|
|
||||||
|
|
||||||
playback = snd_pcm_poll_descriptors_count(pcm->playback);
|
|
||||||
if (playback < 0)
|
|
||||||
return playback;
|
|
||||||
err = snd_pcm_poll_descriptors_revents(pcm->playback, pfds, nfds < (unsigned)playback ? nfds : (unsigned)playback, revents);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (nfds > (unsigned)playback) {
|
|
||||||
err = snd_pcm_poll_descriptors_revents(pcm->capture, pfds + playback, nfds - playback, &_revents);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
*revents |= _revents;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Start a PCM
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_start(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = sndo_pcm_check_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
/* the streams are linked, so use only one stream */
|
|
||||||
return snd_pcm_start(pcm->master);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Stop a PCM dropping pending frames
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_drop(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
/* the streams are linked, so use only one stream */
|
|
||||||
return snd_pcm_drop(pcm->master);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Stop a PCM preserving pending frames
|
|
||||||
* \param pcm PCM handle
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
* \retval -ESTRPIPE a suspend event occurred
|
|
||||||
*
|
|
||||||
* For playback wait for all pending frames to be played and then stop
|
|
||||||
* the PCM.
|
|
||||||
* For capture stop PCM permitting to retrieve residual frames.
|
|
||||||
*/
|
|
||||||
int sndo_pcm_drain(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
/* the streams are linked, so use only one stream */
|
|
||||||
return snd_pcm_drain(pcm->master);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Obtain delay for a running PCM handle
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param delayp Returned delay in frames
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*
|
|
||||||
* Delay is distance between current application frame position and
|
|
||||||
* sound frame position.
|
|
||||||
* It's positive and less than buffer size in normal situation,
|
|
||||||
* negative on playback underrun and greater than buffer size on
|
|
||||||
* capture overrun.
|
|
||||||
*/
|
|
||||||
int sndo_pcm_delay(sndo_pcm_t *pcm, snd_pcm_sframes_t *delayp)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
snd_pcm_sframes_t pdelay, cdelay;
|
|
||||||
|
|
||||||
assert(pcm);
|
|
||||||
assert(delayp);
|
|
||||||
err = sndo_pcm_check_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (pcm->playback)
|
|
||||||
err = snd_pcm_avail_update(pcm->playback);
|
|
||||||
if (err >= 0 && pcm->capture)
|
|
||||||
err = snd_pcm_avail_update(pcm->capture);
|
|
||||||
if (err >= 0 && pcm->playback)
|
|
||||||
err = snd_pcm_delay(pcm->playback, &pdelay);
|
|
||||||
if (err >= 0 && pcm->capture)
|
|
||||||
err = snd_pcm_delay(pcm->capture, &cdelay);
|
|
||||||
if (pdelay > cdelay)
|
|
||||||
pdelay = cdelay;
|
|
||||||
*delayp = pdelay;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Obtain transfer block size (aka period size)
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param tblock Returned transfer block size in frames
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*
|
|
||||||
* All read/write operations must use this transfer block.
|
|
||||||
*/
|
|
||||||
int sndo_pcm_transfer_block(sndo_pcm_t *pcm, snd_pcm_uframes_t *tblock)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
assert(pcm);
|
|
||||||
assert(tblock);
|
|
||||||
err = sndo_pcm_check_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
*tblock = pcm->transfer_block;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Resume from suspend, no samples are lost
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
* \retval -EAGAIN resume can't be proceed immediately (audio hardware is probably still suspended)
|
|
||||||
* \retval -ENOSYS hardware doesn't support this feature
|
|
||||||
*
|
|
||||||
* This function can be used when the stream is in the suspend state
|
|
||||||
* to do the fine resume from this state. Not all hardware supports
|
|
||||||
* this feature, when an -ENOSYS error is returned, use the snd_pcm_prepare
|
|
||||||
* function to recovery.
|
|
||||||
*/
|
|
||||||
int sndo_pcm_resume(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
return snd_pcm_resume(pcm->master);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Wait for a PCM to become ready
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param timeout maximum time in milliseconds to wait
|
|
||||||
* \return a positive value on success otherwise a negative error code
|
|
||||||
* \retval 0 timeout occurred
|
|
||||||
* \retval 1 PCM stream is ready for I/O
|
|
||||||
*/
|
|
||||||
int sndo_pcm_wait(sndo_pcm_t *pcm, int timeout)
|
|
||||||
{
|
|
||||||
struct pollfd pfd[2];
|
|
||||||
unsigned short p_revents, c_revents;
|
|
||||||
int err;
|
|
||||||
err = snd_pcm_poll_descriptors(pcm->playback, &pfd[0], 1);
|
|
||||||
assert(err == 1);
|
|
||||||
err = snd_pcm_poll_descriptors(pcm->capture, &pfd[1], 1);
|
|
||||||
assert(err == 1);
|
|
||||||
err = poll(pfd, 2, timeout);
|
|
||||||
if (err < 0)
|
|
||||||
return -errno;
|
|
||||||
if (err == 0)
|
|
||||||
return 0;
|
|
||||||
do {
|
|
||||||
err = snd_pcm_poll_descriptors_revents(pcm->playback, &pfd[0], 1, &p_revents);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (p_revents & (POLLERR | POLLNVAL))
|
|
||||||
return -EIO;
|
|
||||||
err = snd_pcm_poll_descriptors_revents(pcm->capture, &pfd[1], 1, &c_revents);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (c_revents & (POLLERR | POLLNVAL))
|
|
||||||
return -EIO;
|
|
||||||
if ((p_revents & POLLOUT) && (c_revents & POLLIN))
|
|
||||||
return 1;
|
|
||||||
err = poll(&pfd[(p_revents & POLLOUT) ? 1 : 0], 1, 1);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
} while (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get raw (lowlevel) playback PCM handle
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \return raw (lowlevel) capture PCM handle or NULL
|
|
||||||
*/
|
|
||||||
snd_pcm_t *sndo_pcm_raw_playback(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
return pcm->playback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get raw (lowlevel) capture PCM handle
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \return raw (lowlevel) capture PCM handle or NULL
|
|
||||||
*/
|
|
||||||
snd_pcm_t *sndo_pcm_raw_capture(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
return pcm->capture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Reset all parameters
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_param_reset(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = sndo_pcm_drain(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
pcm->initialized = 0;
|
|
||||||
if (pcm->playback) {
|
|
||||||
err = snd_pcm_hw_params_any(pcm->playback, pcm->p_hw_params);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params_current(pcm->playback, pcm->p_sw_params);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (pcm->capture) {
|
|
||||||
err = snd_pcm_hw_params_any(pcm->capture, pcm->c_hw_params);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params_current(pcm->capture, pcm->c_sw_params);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Set sample access type
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param access access type (interleaved or noninterleaved)
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_param_access(sndo_pcm_t *pcm, enum sndo_pcm_access_type access)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
snd_pcm_access_t native_access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
|
|
||||||
|
|
||||||
switch (access) {
|
|
||||||
case SNDO_PCM_ACCESS_INTERLEAVED: native_access = SND_PCM_ACCESS_MMAP_INTERLEAVED; break;
|
|
||||||
case SNDO_PCM_ACCESS_NONINTERLEAVED: native_access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
err = sndo_pcm_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (pcm->playback) {
|
|
||||||
err = snd_pcm_hw_params_set_access(pcm->playback, pcm->p_hw_params, native_access);
|
|
||||||
if (err < 0) {
|
|
||||||
SNDERR("cannot set requested access for the playback direction");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pcm->capture) {
|
|
||||||
err = snd_pcm_hw_params_set_access(pcm->capture, pcm->c_hw_params, native_access);
|
|
||||||
if (err < 0) {
|
|
||||||
SNDERR("cannot set requested access for the capture direction");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Set stream rate
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param rate requested rate
|
|
||||||
* \param used_rate returned real rate
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_param_rate(sndo_pcm_t *pcm, unsigned int rate, unsigned int *used_rate)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
unsigned int prate = rate, crate = rate;
|
|
||||||
|
|
||||||
err = sndo_pcm_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (pcm->playback) {
|
|
||||||
err = snd_pcm_hw_params_set_rate_near(pcm->playback, pcm->p_hw_params, &prate, 0);
|
|
||||||
if (err < 0) {
|
|
||||||
SNDERR("cannot set requested rate for the playback direction");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pcm->capture) {
|
|
||||||
err = snd_pcm_hw_params_set_rate_near(pcm->capture, pcm->c_hw_params, &crate, 0);
|
|
||||||
if (err < 0) {
|
|
||||||
SNDERR("cannot set requested rate for the capture direction");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (used_rate)
|
|
||||||
*used_rate = pcm->capture ? crate : prate;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Set channels in stream
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param channels requested channels
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_param_channels(sndo_pcm_t *pcm, unsigned int channels)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = sndo_pcm_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (pcm->playback) {
|
|
||||||
err = snd_pcm_hw_params_set_channels(pcm->capture, pcm->p_hw_params, channels);
|
|
||||||
if (err < 0) {
|
|
||||||
SNDERR("cannot set requested channels for the playback direction");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pcm->capture) {
|
|
||||||
err = snd_pcm_hw_params_set_channels(pcm->capture, pcm->c_hw_params, channels);
|
|
||||||
if (err < 0) {
|
|
||||||
SNDERR("cannot set requested channels for the capture direction");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Set stream format
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param rate requested channels
|
|
||||||
* \param used_rate returned real channels
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_param_format(sndo_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_subformat_t subformat)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (subformat != SND_PCM_SUBFORMAT_STD)
|
|
||||||
return -EINVAL;
|
|
||||||
err = snd_pcm_format_physical_width(format);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (err % 8)
|
|
||||||
return -EINVAL;
|
|
||||||
err = sndo_pcm_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (pcm->playback) {
|
|
||||||
err = snd_pcm_hw_params_set_format(pcm->capture, pcm->p_hw_params, format);
|
|
||||||
if (err < 0) {
|
|
||||||
SNDERR("cannot set requested format for the playback direction");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pcm->capture) {
|
|
||||||
err = snd_pcm_hw_params_set_format(pcm->capture, pcm->c_hw_params, format);
|
|
||||||
if (err < 0) {
|
|
||||||
SNDERR("cannot set requested format for the capture direction");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Set stream latency
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param latency requested latency
|
|
||||||
* \param used_latency returned real latency in frames
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*
|
|
||||||
* Note that the result value is only approximate and for one direction.
|
|
||||||
* For example, hardware FIFOs are not counted etc.
|
|
||||||
*/
|
|
||||||
int sndo_pcm_param_latency(sndo_pcm_t *pcm, enum sndo_pcm_latency_type latency, snd_pcm_uframes_t *used_latency)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = sndo_pcm_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
pcm->latency = latency;
|
|
||||||
err = sndo_pcm_check_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (used_latency)
|
|
||||||
*used_latency = pcm->ring_size;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Set xrun behaviour
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param xrun requested behaviour
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_param_xrun(sndo_pcm_t *pcm, enum sndo_pcm_xrun_type xrun)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = sndo_pcm_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
pcm->xrun = xrun;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Begin the playback interleaved frame update
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param ring_buffer returned pointer to actual destination area
|
|
||||||
* \param frames returned maximum count of updated frames
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_pio_ibegin(sndo_pcm_t *pcm, void **ring_buffer, snd_pcm_uframes_t *frames)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
const snd_pcm_channel_area_t *areas;
|
|
||||||
|
|
||||||
err = sndo_pcm_check_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_mmap_begin(pcm->playback, &areas, &pcm->p_offset, frames);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (*frames < pcm->transfer_block) {
|
|
||||||
frames = 0;
|
|
||||||
} else {
|
|
||||||
*frames -= *frames % pcm->transfer_block;
|
|
||||||
*ring_buffer = (char *)areas->addr + (areas->first / 8) + pcm->p_offset * pcm->samplebytes;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Finish the playback interleave frame update (commit data to hardware)
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param frames count of updated frames
|
|
||||||
* \return count of transferred frames on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
snd_pcm_sframes_t sndo_pcm_pio_iend(sndo_pcm_t *pcm, snd_pcm_uframes_t frames)
|
|
||||||
{
|
|
||||||
if (frames <= 0)
|
|
||||||
return -EINVAL;
|
|
||||||
if (frames % pcm->transfer_block)
|
|
||||||
return -EINVAL;
|
|
||||||
return snd_pcm_mmap_commit(pcm->playback, pcm->p_offset, frames);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Begin the playback noninterleaved frame update
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param ring_buffer returned pointer to actual destination area
|
|
||||||
* \param frames returned maximum count of updated frames
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_pio_nbegin(sndo_pcm_t *pcm, void ***ring_buffer, snd_pcm_uframes_t *frames)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
unsigned ch;
|
|
||||||
const snd_pcm_channel_area_t *areas;
|
|
||||||
|
|
||||||
err = sndo_pcm_check_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_mmap_begin(pcm->playback, &areas, &pcm->p_offset, frames);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (*frames < pcm->transfer_block) {
|
|
||||||
frames = 0;
|
|
||||||
} else {
|
|
||||||
*frames -= *frames % pcm->transfer_block;
|
|
||||||
for (ch = 0; ch < pcm->channels; ch++)
|
|
||||||
ring_buffer[ch] = areas->addr + (areas->first / 8) + pcm->p_offset * pcm->samplebytes;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Finish the playback noninterleave frame update (commit data to hardware)
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param frames count of updated frames
|
|
||||||
* \return count of transferred frames on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
snd_pcm_sframes_t sndo_pcm_pio_nend(sndo_pcm_t *pcm, snd_pcm_uframes_t frames)
|
|
||||||
{
|
|
||||||
if (frames <= 0)
|
|
||||||
return -EINVAL;
|
|
||||||
if (frames % pcm->transfer_block)
|
|
||||||
return -EINVAL;
|
|
||||||
return snd_pcm_mmap_commit(pcm->playback, pcm->p_offset, frames);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Begin the capture interleaved frame update
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param ring_buffer returned pointer to actual destination area
|
|
||||||
* \param frames returned maximum count of updated frames
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_cio_ibegin(sndo_pcm_t *pcm, void **ring_buffer, snd_pcm_uframes_t *frames)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
const snd_pcm_channel_area_t *areas;
|
|
||||||
|
|
||||||
err = sndo_pcm_check_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_mmap_begin(pcm->capture, &areas, &pcm->c_offset, frames);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (*frames < pcm->transfer_block) {
|
|
||||||
frames = 0;
|
|
||||||
} else {
|
|
||||||
*frames -= *frames % pcm->transfer_block;
|
|
||||||
*ring_buffer = (char *)areas->addr + (areas->first / 8) + pcm->c_offset * pcm->samplebytes;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Finish the capture interleave frame update (commit data to hardware)
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param frames count of updated frames
|
|
||||||
* \return count of transferred frames on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
snd_pcm_sframes_t sndo_pcm_cio_iend(sndo_pcm_t *pcm, snd_pcm_uframes_t frames)
|
|
||||||
{
|
|
||||||
if (frames <= 0)
|
|
||||||
return -EINVAL;
|
|
||||||
if (frames % pcm->transfer_block)
|
|
||||||
return -EINVAL;
|
|
||||||
return snd_pcm_mmap_commit(pcm->capture, pcm->p_offset, frames);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Begin the capture noninterleaved frame update
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param ring_buffer returned pointer to actual destination area
|
|
||||||
* \param frames returned maximum count of updated frames
|
|
||||||
* \return 0 on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
int sndo_pcm_cio_nbegin(sndo_pcm_t *pcm, void ***ring_buffer, snd_pcm_uframes_t *frames)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
unsigned ch;
|
|
||||||
const snd_pcm_channel_area_t *areas;
|
|
||||||
|
|
||||||
err = sndo_pcm_check_setup(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_mmap_begin(pcm->capture, &areas, &pcm->c_offset, frames);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (*frames < pcm->transfer_block) {
|
|
||||||
frames = 0;
|
|
||||||
} else {
|
|
||||||
*frames -= *frames % pcm->transfer_block;
|
|
||||||
for (ch = 0; ch < pcm->channels; ch++)
|
|
||||||
ring_buffer[ch] = areas->addr + (areas->first / 8) + pcm->c_offset * pcm->samplebytes;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Finish the capture noninterleave frame update (commit data to hardware)
|
|
||||||
* \param pcm ordinary PCM handle
|
|
||||||
* \param frames count of updated frames
|
|
||||||
* \return count of transferred frames on success otherwise a negative error code
|
|
||||||
*/
|
|
||||||
snd_pcm_sframes_t sndo_pcm_cio_nend(sndo_pcm_t *pcm, snd_pcm_uframes_t frames)
|
|
||||||
{
|
|
||||||
if (frames <= 0)
|
|
||||||
return -EINVAL;
|
|
||||||
if (frames % pcm->transfer_block)
|
|
||||||
return -EINVAL;
|
|
||||||
return snd_pcm_mmap_commit(pcm->capture, pcm->c_offset, frames);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* helpers
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int sndo_pcm_setup(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = sndo_pcm_drain(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (!pcm->setting_up) {
|
|
||||||
int err = sndo_pcm_param_reset(pcm);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
pcm->setting_up = 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sndo_pcm_initialize(sndo_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
snd_pcm_uframes_t boundary;
|
|
||||||
snd_pcm_uframes_t p_period_size = ~0UL, c_period_size = ~0UL;
|
|
||||||
snd_pcm_uframes_t p_buffer_size = ~0UL, c_buffer_size = ~0UL;
|
|
||||||
|
|
||||||
if (pcm->playback) {
|
|
||||||
err = snd_pcm_hw_params(pcm->playback, pcm->p_hw_params);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_hw_params_get_period_size(pcm->p_hw_params, &p_period_size, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_hw_params_get_buffer_size(pcm->p_hw_params, &p_buffer_size);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (pcm->capture) {
|
|
||||||
err = snd_pcm_hw_params(pcm->capture, pcm->c_hw_params);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_hw_params_get_period_size(pcm->c_hw_params, &c_period_size, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_hw_params_get_buffer_size(pcm->c_hw_params, &c_buffer_size);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (p_period_size < c_period_size)
|
|
||||||
pcm->transfer_block = p_period_size;
|
|
||||||
else
|
|
||||||
pcm->transfer_block = c_period_size;
|
|
||||||
if (p_buffer_size < c_buffer_size)
|
|
||||||
pcm->ring_size = p_buffer_size;
|
|
||||||
else
|
|
||||||
pcm->ring_size = c_buffer_size;
|
|
||||||
if (pcm->playback) {
|
|
||||||
err = snd_pcm_sw_params_get_boundary(pcm->p_sw_params, &boundary);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params_set_start_threshold(pcm->playback, pcm->p_sw_params, boundary);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params_set_stop_threshold(pcm->playback, pcm->p_sw_params, pcm->xrun == SNDO_PCM_XRUN_IGNORE ? boundary : pcm->ring_size);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params_set_xfer_align(pcm->playback, pcm->p_sw_params, 1);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params_set_avail_min(pcm->playback, pcm->p_sw_params, pcm->transfer_block);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params(pcm->playback, pcm->p_sw_params);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (pcm->capture) {
|
|
||||||
err = snd_pcm_sw_params_get_boundary(pcm->c_sw_params, &boundary);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params_set_start_threshold(pcm->capture, pcm->c_sw_params, boundary);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params_set_stop_threshold(pcm->capture, pcm->c_sw_params, pcm->xrun == SNDO_PCM_XRUN_IGNORE ? boundary : pcm->ring_size);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params_set_xfer_align(pcm->capture, pcm->c_sw_params, 1);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params_set_avail_min(pcm->capture, pcm->c_sw_params, pcm->transfer_block);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
err = snd_pcm_sw_params(pcm->capture, pcm->c_sw_params);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
pcm->initialized = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue