Initial implementation of PCM simple API extension.

This commit is contained in:
Jaroslav Kysela 2004-03-26 16:08:01 +00:00
parent 25f864b059
commit a190b87d94
4 changed files with 292 additions and 2 deletions

View file

@ -1241,6 +1241,14 @@ typedef enum _snd_spcm_xrun_type {
SND_SPCM_XRUN_STOP
} snd_spcm_xrun_type_t;
/** Simple PCM duplex type */
typedef enum _snd_spcm_duplex_type {
/** liberal duplex - the buffer and period sizes might not match */
SND_SPCM_DUPLEX_LIBERAL = 0,
/** pedantic duplex - the buffer and period sizes MUST match */
SND_SPCM_DUPLEX_PEDANTIC
} snd_spcm_duplex_type_t;
int snd_spcm_init(snd_pcm_t *pcm,
unsigned int rate,
unsigned int channels,
@ -1258,7 +1266,13 @@ int snd_spcm_init_duplex(snd_pcm_t *playback_pcm,
snd_pcm_subformat_t subformat,
snd_spcm_latency_t latency,
snd_pcm_access_t access,
snd_spcm_xrun_type_t xrun_type);
snd_spcm_xrun_type_t xrun_type,
snd_spcm_duplex_type_t duplex_type);
int snd_spcm_init_get_params(snd_pcm_t *pcm,
unsigned int *rate,
snd_pcm_uframes_t *buffer_size,
snd_pcm_uframes_t *period_size);
/** \} */

View file

@ -144,3 +144,11 @@ ALSA_0.9.8 {
snd_ctl_elem_remove;
snd_hctl_poll_descriptors_revents;
} ALSA_0.9.7;
ALSA_1.0.4 {
global:
snd_spcm_init;
snd_spcm_init_duplex;
snd_spcm_init_get_params;
} ALSA_0.9.8;

View file

@ -4,7 +4,7 @@ DIST_SUBDIRS = ext scopes
EXTRA_LTLIBRARIES = libpcm.la
libpcm_la_SOURCES = atomic.c mask.c interval.c \
pcm.c pcm_params.c \
pcm.c pcm_params.c pcm_simple.c \
pcm_hw.c pcm_plugin.c pcm_copy.c pcm_linear.c \
pcm_route.c pcm_mulaw.c pcm_alaw.c pcm_adpcm.c \
pcm_rate.c pcm_plug.c pcm_misc.c pcm_mmap.c pcm_multi.c \

268
src/pcm/pcm_simple.c Normal file
View file

@ -0,0 +1,268 @@
/**
* \file pcm/pcm_simple.c
* \ingroup PCM_Simple
* \brief PCM Simple Interface
* \author Jaroslav Kysela <perex@suse.cz>
* \date 2004
*/
/*
*
* 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
*
*/
#include "pcm_local.h"
static int set_buffer_time(snd_spcm_latency_t latency,
unsigned int *buffer_time)
{
switch (latency) {
case SND_SPCM_LATENCY_STANDARD:
*buffer_time = 350000;
break;
case SND_SPCM_LATENCY_MEDIUM:
*buffer_time = 25000;
break;
case SND_SPCM_LATENCY_REALTIME:
*buffer_time = 2500;
break;
default:
return -EINVAL;
}
return 0;
}
static int set_hw_params(snd_pcm_t *pcm,
snd_pcm_hw_params_t *hw_params,
unsigned int *rate,
unsigned int channels,
snd_pcm_format_t format,
snd_pcm_subformat_t subformat,
unsigned int *buffer_time,
unsigned int *period_time,
snd_pcm_access_t access)
{
int err;
/*
* hardware parameters
*/
err = snd_pcm_hw_params_any(pcm, hw_params);
if (err < 0)
return err;
err = snd_pcm_hw_params_set_access(pcm, hw_params, access);
if (err < 0)
return err;
err = snd_pcm_hw_params_set_format(pcm, hw_params, format);
if (err < 0)
return err;
if (subformat != SND_PCM_SUBFORMAT_STD) {
err = snd_pcm_hw_params_set_subformat(pcm, hw_params, subformat);
if (err < 0)
return err;
}
err = snd_pcm_hw_params_set_channels(pcm, hw_params, channels);
if (err < 0)
return err;
err = INTERNAL(snd_pcm_hw_params_set_rate_near)(pcm, hw_params, rate, 0);
if (err < 0)
return err;
err = INTERNAL(snd_pcm_hw_params_set_buffer_time_near)(pcm, hw_params, buffer_time, NULL);
if (err < 0)
return err;
if (period_time == NULL || *period_time == 0) {
unsigned int periods = 3;
err = INTERNAL(snd_pcm_hw_params_set_periods_near)(pcm, hw_params, &periods, NULL);
if (err < 0)
return err;
if (periods == 1)
return -EINVAL;
if (*period_time == 0) {
err = INTERNAL(snd_pcm_hw_params_get_period_time)(hw_params, period_time, NULL);
if (err < 0)
return err;
}
} else {
err = snd_pcm_hw_params_set_period_time(pcm, hw_params, *period_time, 0);
if (err < 0)
return err;
if (*buffer_time == *period_time)
return -EINVAL;
}
err = snd_pcm_hw_params(pcm, hw_params);
if (err < 0)
return err;
return 0;
}
static int set_sw_params(snd_pcm_t *pcm,
snd_pcm_sw_params_t *sw_params,
snd_spcm_xrun_type_t xrun_type)
{
int err;
err = snd_pcm_sw_params_current(pcm, sw_params);
if (err < 0)
return err;
err = snd_pcm_sw_params_set_start_threshold(pcm, sw_params, (pcm->buffer_size / pcm->period_size) * pcm->period_size);
if (err < 0)
return err;
err = snd_pcm_sw_params_set_avail_min(pcm, sw_params, pcm->period_size);
if (err < 0)
return err;
switch (xrun_type) {
case SND_SPCM_XRUN_STOP:
err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->buffer_size);
break;
case SND_SPCM_XRUN_IGNORE:
err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->boundary);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
err = snd_pcm_sw_params_set_xfer_align(pcm, sw_params, 1);
if (err < 0)
return err;
err = snd_pcm_sw_params(pcm, sw_params);
if (err < 0)
return err;
return 0;
}
int snd_spcm_init(snd_pcm_t *pcm,
unsigned int rate,
unsigned int channels,
snd_pcm_format_t format,
snd_pcm_subformat_t subformat,
snd_spcm_latency_t latency,
snd_pcm_access_t access,
snd_spcm_xrun_type_t xrun_type)
{
int err;
snd_pcm_hw_params_t *hw_params;
snd_pcm_sw_params_t *sw_params;
unsigned int rrate;
unsigned int buffer_time;
snd_pcm_hw_params_alloca(&hw_params);
snd_pcm_sw_params_alloca(&sw_params);
assert(pcm);
assert(rate > 5000 && rate < 192000);
assert(channels > 1 && channels < 512);
rrate = rate;
err = set_buffer_time(latency, &buffer_time);
if (err < 0)
return err;
err = set_hw_params(pcm, hw_params,
&rrate, channels, format, subformat,
&buffer_time, NULL, access);
if (err < 0)
return err;
err = set_sw_params(pcm, sw_params, xrun_type);
if (err < 0)
return err;
return 0;
}
int snd_spcm_init_duplex(snd_pcm_t *playback_pcm,
snd_pcm_t *capture_pcm,
unsigned int rate,
unsigned int channels,
snd_pcm_format_t format,
snd_pcm_subformat_t subformat,
snd_spcm_latency_t latency,
snd_pcm_access_t access,
snd_spcm_xrun_type_t xrun_type,
snd_spcm_duplex_type_t duplex_type)
{
int err, i;
snd_pcm_hw_params_t *hw_params;
snd_pcm_sw_params_t *sw_params;
unsigned int rrate;
unsigned int xbuffer_time, buffer_time[2];
unsigned int period_time[2];
snd_pcm_t *pcms[2];
snd_pcm_hw_params_alloca(&hw_params);
snd_pcm_sw_params_alloca(&sw_params);
assert(playback_pcm);
assert(capture_pcm);
assert(rate > 5000 && rate < 192000);
assert(channels > 1 && channels < 512);
pcms[0] = playback_pcm;
pcms[1] = capture_pcm;
/*
* hardware parameters
*/
err = set_buffer_time(latency, &xbuffer_time);
if (err < 0)
return err;
for (i = 0; i < 2; i++) {
buffer_time[i] = xbuffer_time;
period_time[i] = i > 0 ? period_time[0] : 0;
rrate = rate;
err = set_hw_params(pcms[i], hw_params,
&rrate, channels, format, subformat,
&buffer_time[i], &period_time[i], access);
if (err < 0)
return err;
}
if (buffer_time[0] == buffer_time[1] &&
period_time[0] == period_time[1])
goto __sw_params;
if (duplex_type == SND_SPCM_DUPLEX_LIBERAL)
goto __sw_params;
/* FIXME: */
return -EINVAL;
/*
* software parameters
*/
__sw_params:
for (i = 0; i < 2; i++) {
err = set_sw_params(pcms[i], sw_params, xrun_type);
if (err < 0)
return err;
}
return 0;
}
int snd_spcm_init_get_params(snd_pcm_t *pcm,
unsigned int *rate,
snd_pcm_uframes_t *buffer_size,
snd_pcm_uframes_t *period_size)
{
assert(pcm);
if (!pcm->setup)
return -EBADFD;
if (rate)
*rate = pcm->rate;
if (buffer_size)
*buffer_size = pcm->buffer_size;
if (period_size)
*period_size = pcm->period_size;
return 0;
}