|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \file pcm/pcm_rate.c
|
|
Packit Service |
db8eaa |
* \ingroup PCM_Plugins
|
|
Packit Service |
db8eaa |
* \brief PCM Rate Plugin Interface
|
|
Packit Service |
db8eaa |
* \author Abramo Bagnara <abramo@alsa-project.org>
|
|
Packit Service |
db8eaa |
* \author Jaroslav Kysela <perex@perex.cz>
|
|
Packit Service |
db8eaa |
* \date 2000-2004
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
/*
|
|
Packit Service |
db8eaa |
* PCM - Rate conversion
|
|
Packit Service |
db8eaa |
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
|
|
Packit Service |
db8eaa |
* 2004 by Jaroslav Kysela <perex@perex.cz>
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* This library is free software; you can redistribute it and/or modify
|
|
Packit Service |
db8eaa |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit Service |
db8eaa |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
db8eaa |
* the License, or (at your option) any later version.
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
db8eaa |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
db8eaa |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
db8eaa |
* GNU Lesser General Public License for more details.
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
db8eaa |
* License along with this library; if not, write to the Free Software
|
|
Packit Service |
db8eaa |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
#include <inttypes.h>
|
|
Packit Service |
db8eaa |
#include "bswap.h"
|
|
Packit Service |
db8eaa |
#include "pcm_local.h"
|
|
Packit Service |
db8eaa |
#include "pcm_plugin.h"
|
|
Packit Service |
db8eaa |
#include "pcm_rate.h"
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#include "plugin_ops.h"
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#if 0
|
|
Packit Service |
db8eaa |
#define DEBUG_REFINE
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#ifndef PIC
|
|
Packit Service |
db8eaa |
/* entry for static linking */
|
|
Packit Service |
db8eaa |
const char *_snd_module_pcm_rate = "";
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#ifndef DOC_HIDDEN
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
typedef struct _snd_pcm_rate snd_pcm_rate_t;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
struct _snd_pcm_rate {
|
|
Packit Service |
db8eaa |
snd_pcm_generic_t gen;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t appl_ptr, hw_ptr, last_slave_hw_ptr;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t last_commit_ptr;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t orig_avail_min;
|
|
Packit Service |
db8eaa |
snd_pcm_sw_params_t sw_params;
|
|
Packit Service |
db8eaa |
snd_pcm_format_t sformat;
|
|
Packit Service |
db8eaa |
unsigned int srate;
|
|
Packit Service |
db8eaa |
snd_pcm_channel_area_t *pareas; /* areas for splitted period (rate pcm) */
|
|
Packit Service |
db8eaa |
snd_pcm_channel_area_t *sareas; /* areas for splitted period (slave pcm) */
|
|
Packit Service |
db8eaa |
snd_pcm_rate_info_t info;
|
|
Packit Service |
db8eaa |
void *open_func;
|
|
Packit Service |
db8eaa |
void *obj;
|
|
Packit Service |
db8eaa |
snd_pcm_rate_ops_t ops;
|
|
Packit Service |
db8eaa |
unsigned int get_idx;
|
|
Packit Service |
db8eaa |
unsigned int put_idx;
|
|
Packit Service |
db8eaa |
int16_t *src_buf;
|
|
Packit Service |
db8eaa |
int16_t *dst_buf;
|
|
Packit Service |
db8eaa |
int start_pending; /* start is triggered but not commited to slave */
|
|
Packit Service |
db8eaa |
snd_htimestamp_t trigger_tstamp;
|
|
Packit Service |
db8eaa |
unsigned int plugin_version;
|
|
Packit Service |
db8eaa |
unsigned int rate_min, rate_max;
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#define SND_PCM_RATE_PLUGIN_VERSION_OLD 0x010001 /* old rate plugin */
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#endif /* DOC_HIDDEN */
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
|
|
Packit Service |
db8eaa |
snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR };
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
|
|
Packit Service |
db8eaa |
&access_mask);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT,
|
|
Packit Service |
db8eaa |
&format_mask);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
if (rate->rate_min) {
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_RATE,
|
|
Packit Service |
db8eaa |
rate->rate_min, 0);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (rate->rate_max) {
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_param_set_max(params, SND_PCM_HW_PARAM_RATE,
|
|
Packit Service |
db8eaa |
rate->rate_max, 0);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
|
|
Packit Service |
db8eaa |
_snd_pcm_hw_params_any(sparams);
|
|
Packit Service |
db8eaa |
_snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
|
|
Packit Service |
db8eaa |
&saccess_mask);
|
|
Packit Service |
db8eaa |
if (rate->sformat != SND_PCM_FORMAT_UNKNOWN) {
|
|
Packit Service |
db8eaa |
_snd_pcm_hw_params_set_format(sparams, rate->sformat);
|
|
Packit Service |
db8eaa |
_snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
_snd_pcm_hw_param_set_minmax(sparams, SND_PCM_HW_PARAM_RATE,
|
|
Packit Service |
db8eaa |
rate->srate, 0, rate->srate + 1, -1);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_t *sparams)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_interval_t t, buffer_size;
|
|
Packit Service |
db8eaa |
const snd_interval_t *srate, *crate;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARBIT_PERIOD_TIME |
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARBIT_TICK_TIME);
|
|
Packit Service |
db8eaa |
if (rate->sformat == SND_PCM_FORMAT_UNKNOWN)
|
|
Packit Service |
db8eaa |
links |= (SND_PCM_HW_PARBIT_FORMAT |
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARBIT_SUBFORMAT |
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARBIT_SAMPLE_BITS |
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARBIT_FRAME_BITS);
|
|
Packit Service |
db8eaa |
snd_interval_copy(&buffer_size, snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE));
|
|
Packit Service |
db8eaa |
snd_interval_unfloor(&buffer_size);
|
|
Packit Service |
db8eaa |
crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE);
|
|
Packit Service |
db8eaa |
srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE);
|
|
Packit Service |
db8eaa |
snd_interval_muldiv(&buffer_size, srate, crate, &t);
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_param_set_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_params_refine(sparams, links, params);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_t *sparams)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_interval_t t;
|
|
Packit Service |
db8eaa |
#ifdef DEBUG_REFINE
|
|
Packit Service |
db8eaa |
snd_output_t *out;
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
const snd_interval_t *sbuffer_size, *buffer_size;
|
|
Packit Service |
db8eaa |
const snd_interval_t *srate, *crate;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARBIT_PERIOD_TIME |
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARBIT_TICK_TIME);
|
|
Packit Service |
db8eaa |
if (rate->sformat == SND_PCM_FORMAT_UNKNOWN)
|
|
Packit Service |
db8eaa |
links |= (SND_PCM_HW_PARBIT_FORMAT |
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARBIT_SUBFORMAT |
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARBIT_SAMPLE_BITS |
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARBIT_FRAME_BITS);
|
|
Packit Service |
db8eaa |
sbuffer_size = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE);
|
|
Packit Service |
db8eaa |
crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE);
|
|
Packit Service |
db8eaa |
srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE);
|
|
Packit Service |
db8eaa |
snd_interval_muldiv(sbuffer_size, crate, srate, &t);
|
|
Packit Service |
db8eaa |
snd_interval_floor(&t);
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_param_set_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
buffer_size = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE);
|
|
Packit Service |
db8eaa |
/*
|
|
Packit Service |
db8eaa |
* this condition probably needs more work:
|
|
Packit Service |
db8eaa |
* in case when the buffer_size is known and we are looking
|
|
Packit Service |
db8eaa |
* for best period_size, we should prefer situation when
|
|
Packit Service |
db8eaa |
* (buffer_size / period_size) * period_size == buffer_size
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
if (snd_interval_single(buffer_size) && buffer_size->integer) {
|
|
Packit Service |
db8eaa |
snd_interval_t *period_size;
|
|
Packit Service |
db8eaa |
period_size = (snd_interval_t *)snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE);
|
|
Packit Service |
db8eaa |
if (!snd_interval_checkempty(period_size) &&
|
|
Packit Service |
db8eaa |
period_size->openmin && period_size->openmax &&
|
|
Packit Service |
db8eaa |
period_size->min + 1 == period_size->max) {
|
|
Packit Service |
db8eaa |
if (period_size->min > 0 && (buffer_size->min / period_size->min) * period_size->min == buffer_size->min) {
|
|
Packit Service |
db8eaa |
snd_interval_set_value(period_size, period_size->min);
|
|
Packit Service |
db8eaa |
} else if ((buffer_size->max / period_size->max) * period_size->max == buffer_size->max) {
|
|
Packit Service |
db8eaa |
snd_interval_set_value(period_size, period_size->max);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
#ifdef DEBUG_REFINE
|
|
Packit Service |
db8eaa |
snd_output_stdio_attach(&out, stderr, 0);
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "REFINE (params):\n");
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_dump(params, out);
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "REFINE (slave params):\n");
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_dump(sparams, out);
|
|
Packit Service |
db8eaa |
snd_output_close(out);
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
err = _snd_pcm_hw_params_refine(params, links, sparams);
|
|
Packit Service |
db8eaa |
#ifdef DEBUG_REFINE
|
|
Packit Service |
db8eaa |
snd_output_stdio_attach(&out, stderr, 0);
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "********************\n");
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "REFINE (params) (%i):\n", err);
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_dump(params, out);
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "REFINE (slave params):\n");
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_dump(sparams, out);
|
|
Packit Service |
db8eaa |
snd_output_close(out);
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm,
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_t *params)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return snd_pcm_hw_refine_slave(pcm, params,
|
|
Packit Service |
db8eaa |
snd_pcm_rate_hw_refine_cprepare,
|
|
Packit Service |
db8eaa |
snd_pcm_rate_hw_refine_cchange,
|
|
Packit Service |
db8eaa |
snd_pcm_rate_hw_refine_sprepare,
|
|
Packit Service |
db8eaa |
snd_pcm_rate_hw_refine_schange,
|
|
Packit Service |
db8eaa |
snd_pcm_generic_hw_refine);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_t *slave = rate->gen.slave;
|
|
Packit Service |
db8eaa |
snd_pcm_rate_side_info_t *sinfo, *cinfo;
|
|
Packit Service |
db8eaa |
unsigned int channels, cwidth, swidth, chn;
|
|
Packit Service |
db8eaa |
int err = snd_pcm_hw_params_slave(pcm, params,
|
|
Packit Service |
db8eaa |
snd_pcm_rate_hw_refine_cchange,
|
|
Packit Service |
db8eaa |
snd_pcm_rate_hw_refine_sprepare,
|
|
Packit Service |
db8eaa |
snd_pcm_rate_hw_refine_schange,
|
|
Packit Service |
db8eaa |
snd_pcm_generic_hw_params);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit Service |
db8eaa |
cinfo = &rate->info.in;
|
|
Packit Service |
db8eaa |
sinfo = &rate->info.out;
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
sinfo = &rate->info.in;
|
|
Packit Service |
db8eaa |
cinfo = &rate->info.out;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
err = INTERNAL(snd_pcm_hw_params_get_format)(params, &cinfo->format);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = INTERNAL(snd_pcm_hw_params_get_rate)(params, &cinfo->rate, 0);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = INTERNAL(snd_pcm_hw_params_get_period_size)(params, &cinfo->period_size, 0);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &cinfo->buffer_size);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = INTERNAL(snd_pcm_hw_params_get_channels)(params, &channels);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
rate->info.channels = channels;
|
|
Packit Service |
db8eaa |
sinfo->format = slave->format;
|
|
Packit Service |
db8eaa |
sinfo->rate = slave->rate;
|
|
Packit Service |
db8eaa |
sinfo->buffer_size = slave->buffer_size;
|
|
Packit Service |
db8eaa |
sinfo->period_size = slave->period_size;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (CHECK_SANITY(rate->pareas)) {
|
|
Packit Service |
db8eaa |
SNDMSG("rate plugin already in use");
|
|
Packit Service |
db8eaa |
return -EBUSY;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
err = rate->ops.init(rate->obj, &rate->info);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
rate->pareas = malloc(2 * channels * sizeof(*rate->pareas));
|
|
Packit Service |
db8eaa |
if (rate->pareas == NULL)
|
|
Packit Service |
db8eaa |
goto error;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
cwidth = snd_pcm_format_physical_width(cinfo->format);
|
|
Packit Service |
db8eaa |
swidth = snd_pcm_format_physical_width(sinfo->format);
|
|
Packit Service |
db8eaa |
rate->pareas[0].addr = malloc(((cwidth * channels * cinfo->period_size) / 8) +
|
|
Packit Service |
db8eaa |
((swidth * channels * sinfo->period_size) / 8));
|
|
Packit Service |
db8eaa |
if (rate->pareas[0].addr == NULL)
|
|
Packit Service |
db8eaa |
goto error;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
rate->sareas = rate->pareas + channels;
|
|
Packit Service |
db8eaa |
rate->sareas[0].addr = (char *)rate->pareas[0].addr + ((cwidth * channels * cinfo->period_size) / 8);
|
|
Packit Service |
db8eaa |
for (chn = 0; chn < channels; chn++) {
|
|
Packit Service |
db8eaa |
rate->pareas[chn].addr = (char *)rate->pareas[0].addr + (cwidth * chn * cinfo->period_size) / 8;
|
|
Packit Service |
db8eaa |
rate->pareas[chn].first = 0;
|
|
Packit Service |
db8eaa |
rate->pareas[chn].step = cwidth;
|
|
Packit Service |
db8eaa |
rate->sareas[chn].addr = (char *)rate->sareas[0].addr + (swidth * chn * sinfo->period_size) / 8;
|
|
Packit Service |
db8eaa |
rate->sareas[chn].first = 0;
|
|
Packit Service |
db8eaa |
rate->sareas[chn].step = swidth;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (rate->ops.convert_s16) {
|
|
Packit Service |
db8eaa |
rate->get_idx = snd_pcm_linear_get_index(rate->info.in.format, SND_PCM_FORMAT_S16);
|
|
Packit Service |
db8eaa |
rate->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, rate->info.out.format);
|
|
Packit Service |
db8eaa |
free(rate->src_buf);
|
|
Packit Service |
db8eaa |
rate->src_buf = malloc(channels * rate->info.in.period_size * 2);
|
|
Packit Service |
db8eaa |
free(rate->dst_buf);
|
|
Packit Service |
db8eaa |
rate->dst_buf = malloc(channels * rate->info.out.period_size * 2);
|
|
Packit Service |
db8eaa |
if (! rate->src_buf || ! rate->dst_buf)
|
|
Packit Service |
db8eaa |
goto error;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
error:
|
|
Packit Service |
db8eaa |
if (rate->pareas) {
|
|
Packit Service |
db8eaa |
free(rate->pareas[0].addr);
|
|
Packit Service |
db8eaa |
free(rate->pareas);
|
|
Packit Service |
db8eaa |
rate->pareas = NULL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (rate->ops.free)
|
|
Packit Service |
db8eaa |
rate->ops.free(rate->obj);
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_hw_free(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
if (rate->pareas) {
|
|
Packit Service |
db8eaa |
free(rate->pareas[0].addr);
|
|
Packit Service |
db8eaa |
free(rate->pareas);
|
|
Packit Service |
db8eaa |
rate->pareas = NULL;
|
|
Packit Service |
db8eaa |
rate->sareas = NULL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (rate->ops.free)
|
|
Packit Service |
db8eaa |
rate->ops.free(rate->obj);
|
|
Packit Service |
db8eaa |
free(rate->src_buf);
|
|
Packit Service |
db8eaa |
free(rate->dst_buf);
|
|
Packit Service |
db8eaa |
rate->src_buf = rate->dst_buf = NULL;
|
|
Packit Service |
db8eaa |
return snd_pcm_hw_free(rate->gen.slave);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void recalc(snd_pcm_t *pcm, snd_pcm_uframes_t *val)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_t *slave = rate->gen.slave;
|
|
Packit Service |
db8eaa |
unsigned long div;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (*val == pcm->buffer_size) {
|
|
Packit Service |
db8eaa |
*val = slave->buffer_size;
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
div = *val / pcm->period_size;
|
|
Packit Service |
db8eaa |
if (div * pcm->period_size == *val)
|
|
Packit Service |
db8eaa |
*val = div * slave->period_size;
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
*val = muldiv_near(*val, slave->period_size, pcm->period_size);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_t *slave = rate->gen.slave;
|
|
Packit Service |
db8eaa |
snd_pcm_sw_params_t *sparams;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t boundary1, boundary2, sboundary;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
sparams = &rate->sw_params;
|
|
Packit Service |
db8eaa |
err = snd_pcm_sw_params_current(slave, sparams);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
sboundary = sparams->boundary;
|
|
Packit Service |
db8eaa |
*sparams = *params;
|
|
Packit Service |
db8eaa |
boundary1 = pcm->buffer_size;
|
|
Packit Service |
db8eaa |
boundary2 = slave->buffer_size;
|
|
Packit Service |
db8eaa |
while (boundary1 * 2 <= LONG_MAX - pcm->buffer_size &&
|
|
Packit Service |
db8eaa |
boundary2 * 2 <= LONG_MAX - slave->buffer_size) {
|
|
Packit Service |
db8eaa |
boundary1 *= 2;
|
|
Packit Service |
db8eaa |
boundary2 *= 2;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
params->boundary = boundary1;
|
|
Packit Service |
db8eaa |
sparams->boundary = sboundary;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (rate->ops.adjust_pitch)
|
|
Packit Service |
db8eaa |
rate->ops.adjust_pitch(rate->obj, &rate->info);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
recalc(pcm, &sparams->avail_min);
|
|
Packit Service |
db8eaa |
rate->orig_avail_min = sparams->avail_min;
|
|
Packit Service |
db8eaa |
recalc(pcm, &sparams->start_threshold);
|
|
Packit Service |
db8eaa |
if (sparams->avail_min < 1) sparams->avail_min = 1;
|
|
Packit Service |
db8eaa |
if (sparams->start_threshold <= slave->buffer_size) {
|
|
Packit Service |
db8eaa |
if (sparams->start_threshold > (slave->buffer_size / sparams->avail_min) * sparams->avail_min)
|
|
Packit Service |
db8eaa |
sparams->start_threshold = (slave->buffer_size / sparams->avail_min) * sparams->avail_min;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (sparams->stop_threshold >= params->boundary) {
|
|
Packit Service |
db8eaa |
sparams->stop_threshold = sparams->boundary;
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
recalc(pcm, &sparams->stop_threshold);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
recalc(pcm, &sparams->silence_threshold);
|
|
Packit Service |
db8eaa |
if (sparams->silence_size >= params->boundary) {
|
|
Packit Service |
db8eaa |
sparams->silence_size = sparams->boundary;
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
recalc(pcm, &sparams->silence_size);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return snd_pcm_sw_params(slave, sparams);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_init(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (rate->ops.reset)
|
|
Packit Service |
db8eaa |
rate->ops.reset(rate->obj);
|
|
Packit Service |
db8eaa |
rate->last_commit_ptr = 0;
|
|
Packit Service |
db8eaa |
rate->start_pending = 0;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void convert_to_s16(snd_pcm_rate_t *rate, int16_t *buf,
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *areas,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t offset, unsigned int frames,
|
|
Packit Service |
db8eaa |
unsigned int channels)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
#ifndef DOC_HIDDEN
|
|
Packit Service |
db8eaa |
#define GET16_LABELS
|
|
Packit Service |
db8eaa |
#include "plugin_ops.h"
|
|
Packit Service |
db8eaa |
#undef GET16_LABELS
|
|
Packit Service |
db8eaa |
#endif /* DOC_HIDDEN */
|
|
Packit Service |
db8eaa |
void *get = get16_labels[rate->get_idx];
|
|
Packit Service |
db8eaa |
const char *src;
|
|
Packit Service |
db8eaa |
int16_t sample;
|
|
Packit Service |
db8eaa |
const char *srcs[channels];
|
|
Packit Service |
db8eaa |
int src_step[channels];
|
|
Packit Service |
db8eaa |
unsigned int c;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
for (c = 0; c < channels; c++) {
|
|
Packit Service |
db8eaa |
srcs[c] = snd_pcm_channel_area_addr(areas + c, offset);
|
|
Packit Service |
db8eaa |
src_step[c] = snd_pcm_channel_area_step(areas + c);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
while (frames--) {
|
|
Packit Service |
db8eaa |
for (c = 0; c < channels; c++) {
|
|
Packit Service |
db8eaa |
src = srcs[c];
|
|
Packit Service |
db8eaa |
goto *get;
|
|
Packit Service |
db8eaa |
#ifndef DOC_HIDDEN
|
|
Packit Service |
db8eaa |
#define GET16_END after_get
|
|
Packit Service |
db8eaa |
#include "plugin_ops.h"
|
|
Packit Service |
db8eaa |
#undef GET16_END
|
|
Packit Service |
db8eaa |
#endif /* DOC_HIDDEN */
|
|
Packit Service |
db8eaa |
after_get:
|
|
Packit Service |
db8eaa |
*buf++ = sample;
|
|
Packit Service |
db8eaa |
srcs[c] += src_step[c];
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void convert_from_s16(snd_pcm_rate_t *rate, const int16_t *buf,
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *areas,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t offset, unsigned int frames,
|
|
Packit Service |
db8eaa |
unsigned int channels)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
#ifndef DOC_HIDDEN
|
|
Packit Service |
db8eaa |
#define PUT16_LABELS
|
|
Packit Service |
db8eaa |
#include "plugin_ops.h"
|
|
Packit Service |
db8eaa |
#undef PUT16_LABELS
|
|
Packit Service |
db8eaa |
#endif /* DOC_HIDDEN */
|
|
Packit Service |
db8eaa |
void *put = put16_labels[rate->put_idx];
|
|
Packit Service |
db8eaa |
char *dst;
|
|
Packit Service |
db8eaa |
int16_t sample;
|
|
Packit Service |
db8eaa |
char *dsts[channels];
|
|
Packit Service |
db8eaa |
int dst_step[channels];
|
|
Packit Service |
db8eaa |
unsigned int c;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
for (c = 0; c < channels; c++) {
|
|
Packit Service |
db8eaa |
dsts[c] = snd_pcm_channel_area_addr(areas + c, offset);
|
|
Packit Service |
db8eaa |
dst_step[c] = snd_pcm_channel_area_step(areas + c);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
while (frames--) {
|
|
Packit Service |
db8eaa |
for (c = 0; c < channels; c++) {
|
|
Packit Service |
db8eaa |
dst = dsts[c];
|
|
Packit Service |
db8eaa |
sample = *buf++;
|
|
Packit Service |
db8eaa |
goto *put;
|
|
Packit Service |
db8eaa |
#ifndef DOC_HIDDEN
|
|
Packit Service |
db8eaa |
#define PUT16_END after_put
|
|
Packit Service |
db8eaa |
#include "plugin_ops.h"
|
|
Packit Service |
db8eaa |
#undef PUT16_END
|
|
Packit Service |
db8eaa |
#endif /* DOC_HIDDEN */
|
|
Packit Service |
db8eaa |
after_put:
|
|
Packit Service |
db8eaa |
dsts[c] += dst_step[c];
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void do_convert(const snd_pcm_channel_area_t *dst_areas,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t dst_offset, unsigned int dst_frames,
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *src_areas,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t src_offset, unsigned int src_frames,
|
|
Packit Service |
db8eaa |
unsigned int channels,
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
if (rate->ops.convert_s16) {
|
|
Packit Service |
db8eaa |
const int16_t *src;
|
|
Packit Service |
db8eaa |
int16_t *dst;
|
|
Packit Service |
db8eaa |
if (! rate->src_buf)
|
|
Packit Service |
db8eaa |
src = (int16_t *)src_areas->addr + src_offset * channels;
|
|
Packit Service |
db8eaa |
else {
|
|
Packit Service |
db8eaa |
convert_to_s16(rate, rate->src_buf, src_areas, src_offset,
|
|
Packit Service |
db8eaa |
src_frames, channels);
|
|
Packit Service |
db8eaa |
src = rate->src_buf;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (! rate->dst_buf)
|
|
Packit Service |
db8eaa |
dst = (int16_t *)dst_areas->addr + dst_offset * channels;
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
dst = rate->dst_buf;
|
|
Packit Service |
db8eaa |
rate->ops.convert_s16(rate->obj, dst, dst_frames, src, src_frames);
|
|
Packit Service |
db8eaa |
if (dst == rate->dst_buf)
|
|
Packit Service |
db8eaa |
convert_from_s16(rate, rate->dst_buf, dst_areas, dst_offset,
|
|
Packit Service |
db8eaa |
dst_frames, channels);
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
rate->ops.convert(rate->obj, dst_areas, dst_offset, dst_frames,
|
|
Packit Service |
db8eaa |
src_areas, src_offset, src_frames);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static inline void
|
|
Packit Service |
db8eaa |
snd_pcm_rate_write_areas1(snd_pcm_t *pcm,
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *areas,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t offset,
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *slave_areas,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t slave_offset)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
do_convert(slave_areas, slave_offset, rate->gen.slave->period_size,
|
|
Packit Service |
db8eaa |
areas, offset, pcm->period_size,
|
|
Packit Service |
db8eaa |
pcm->channels, rate);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static inline void
|
|
Packit Service |
db8eaa |
snd_pcm_rate_read_areas1(snd_pcm_t *pcm,
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *areas,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t offset,
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *slave_areas,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t slave_offset)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
do_convert(areas, offset, pcm->period_size,
|
|
Packit Service |
db8eaa |
slave_areas, slave_offset, rate->gen.slave->period_size,
|
|
Packit Service |
db8eaa |
pcm->channels, rate);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static inline void snd_pcm_rate_sync_hwptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
45dc4a |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
45dc4a |
|
|
Packit Service |
45dc4a |
snd_pcm_sframes_t slave_hw_ptr_diff = slave_hw_ptr - rate->last_slave_hw_ptr;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t last_slave_hw_ptr_frac;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
|
|
Packit Service |
db8eaa |
return;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
45dc4a |
if (slave_hw_ptr_diff < 0)
|
|
Packit Service |
45dc4a |
slave_hw_ptr_diff += rate->gen.slave->boundary; /* slave boundary wraparound */
|
|
Packit Service |
45dc4a |
else if (slave_hw_ptr_diff == 0)
|
|
Packit Service |
db8eaa |
return;
|
|
Packit Service |
db8eaa |
last_slave_hw_ptr_frac = rate->last_slave_hw_ptr % rate->gen.slave->period_size;
|
|
Packit Service |
db8eaa |
/* While handling fraction part fo slave period, rounded value will be
|
|
Packit Service |
db8eaa |
* introduced by input_frames().
|
|
Packit Service |
db8eaa |
* To eliminate rounding issue on rate->hw_ptr, subtract last rounded
|
|
Packit Service |
db8eaa |
* value from rate->hw_ptr and add new rounded value of present
|
|
Packit Service |
db8eaa |
* slave_hw_ptr fraction part to rate->hw_ptr. Hence,
|
|
Packit Service |
db8eaa |
* rate->hw_ptr += [ (no. of updated slave periods * pcm rate period size) -
|
|
Packit Service |
db8eaa |
* fractional part of last_slave_hw_ptr rounded value +
|
|
Packit Service |
db8eaa |
* fractional part of updated slave hw ptr's rounded value ]
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
rate->hw_ptr += (
|
|
Packit Service |
db8eaa |
(((last_slave_hw_ptr_frac + slave_hw_ptr_diff) / rate->gen.slave->period_size) * pcm->period_size) -
|
|
Packit Service |
db8eaa |
rate->ops.input_frames(rate->obj, last_slave_hw_ptr_frac) +
|
|
Packit Service |
db8eaa |
rate->ops.input_frames(rate->obj, (last_slave_hw_ptr_frac + slave_hw_ptr_diff) % rate->gen.slave->period_size));
|
|
Packit Service |
db8eaa |
rate->last_slave_hw_ptr = slave_hw_ptr;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
rate->hw_ptr %= pcm->boundary;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static inline void snd_pcm_rate_sync_hwptr(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_rate_sync_hwptr0(pcm, *rate->gen.slave->hw.ptr);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_hwsync(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
int err = snd_pcm_hwsync(rate->gen.slave);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
snd_pcm_rate_sync_hwptr(pcm);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_pcm_uframes_t snd_pcm_rate_playback_internal_delay(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
45dc4a |
if (rate->appl_ptr < rate->last_commit_ptr) {
|
|
Packit Service |
45dc4a |
return rate->appl_ptr - rate->last_commit_ptr + pcm->boundary;
|
|
Packit Service |
45dc4a |
} else {
|
|
Packit Service |
45dc4a |
return rate->appl_ptr - rate->last_commit_ptr;
|
|
Packit Service |
45dc4a |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t slave_delay;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
snd_pcm_rate_hwsync(pcm);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = snd_pcm_delay(rate->gen.slave, &slave_delay);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit Service |
db8eaa |
*delayp = rate->ops.input_frames(rate->obj, slave_delay)
|
|
Packit Service |
db8eaa |
+ snd_pcm_rate_playback_internal_delay(pcm);
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
*delayp = rate->ops.output_frames(rate->obj, slave_delay)
|
|
Packit Service |
45dc4a |
+ snd_pcm_mmap_capture_hw_avail(pcm);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_prepare(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = snd_pcm_prepare(rate->gen.slave);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
*pcm->hw.ptr = 0;
|
|
Packit Service |
db8eaa |
*pcm->appl.ptr = 0;
|
|
Packit Service |
db8eaa |
rate->last_slave_hw_ptr = 0;
|
|
Packit Service |
db8eaa |
err = snd_pcm_rate_init(pcm);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_reset(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
err = snd_pcm_reset(rate->gen.slave);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
*pcm->hw.ptr = 0;
|
|
Packit Service |
db8eaa |
*pcm->appl.ptr = 0;
|
|
Packit Service |
db8eaa |
rate->last_slave_hw_ptr = 0;
|
|
Packit Service |
db8eaa |
err = snd_pcm_rate_init(pcm);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_pcm_sframes_t snd_pcm_rate_rewindable(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_pcm_sframes_t snd_pcm_rate_forwardable(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_pcm_sframes_t snd_pcm_rate_rewind(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t frames ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_pcm_sframes_t snd_pcm_rate_forward(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t frames ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_commit_area(snd_pcm_t *pcm, snd_pcm_rate_t *rate,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t appl_offset,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t size,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t slave_size)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset;
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *areas;
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *slave_areas;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t slave_offset, xfer;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t slave_frames = ULONG_MAX;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t result;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
areas = snd_pcm_mmap_areas(pcm);
|
|
Packit Service |
db8eaa |
if (cont >= size) {
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
if (slave_frames < slave_size) {
|
|
Packit Service |
db8eaa |
snd_pcm_rate_write_areas1(pcm, areas, appl_offset, rate->sareas, 0);
|
|
Packit Service |
db8eaa |
goto __partial;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
snd_pcm_rate_write_areas1(pcm, areas, appl_offset,
|
|
Packit Service |
db8eaa |
slave_areas, slave_offset);
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, slave_size);
|
|
Packit Service |
db8eaa |
if (result < (snd_pcm_sframes_t)slave_size) {
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
result = snd_pcm_rewind(rate->gen.slave, result);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
snd_pcm_areas_copy(rate->pareas, 0,
|
|
Packit Service |
db8eaa |
areas, appl_offset,
|
|
Packit Service |
db8eaa |
pcm->channels, cont,
|
|
Packit Service |
db8eaa |
pcm->format);
|
|
Packit Service |
db8eaa |
snd_pcm_areas_copy(rate->pareas, cont,
|
|
Packit Service |
db8eaa |
areas, 0,
|
|
Packit Service |
db8eaa |
pcm->channels, size - cont,
|
|
Packit Service |
db8eaa |
pcm->format);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
snd_pcm_rate_write_areas1(pcm, rate->pareas, 0, rate->sareas, 0);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* ok, commit first fragment */
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
__partial:
|
|
Packit Service |
45dc4a |
xfer = 0;
|
|
Packit Service |
db8eaa |
cont = slave_frames;
|
|
Packit Service |
db8eaa |
if (cont > slave_size)
|
|
Packit Service |
db8eaa |
cont = slave_size;
|
|
Packit Service |
db8eaa |
snd_pcm_areas_copy(slave_areas, slave_offset,
|
|
Packit Service |
db8eaa |
rate->sareas, 0,
|
|
Packit Service |
db8eaa |
pcm->channels, cont,
|
|
Packit Service |
db8eaa |
rate->gen.slave->format);
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont);
|
|
Packit Service |
db8eaa |
if (result < (snd_pcm_sframes_t)cont) {
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
result = snd_pcm_rewind(rate->gen.slave, result);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
xfer = cont;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (xfer == slave_size)
|
|
Packit Service |
db8eaa |
goto commit_done;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* commit second fragment */
|
|
Packit Service |
db8eaa |
cont = slave_size - cont;
|
|
Packit Service |
db8eaa |
slave_frames = cont;
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
#if 0
|
|
Packit Service |
db8eaa |
if (slave_offset) {
|
|
Packit Service |
db8eaa |
SNDERR("non-zero slave_offset %ld", slave_offset);
|
|
Packit Service |
db8eaa |
return -EIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
snd_pcm_areas_copy(slave_areas, slave_offset,
|
|
Packit Service |
db8eaa |
rate->sareas, xfer,
|
|
Packit Service |
db8eaa |
pcm->channels, cont,
|
|
Packit Service |
db8eaa |
rate->gen.slave->format);
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont);
|
|
Packit Service |
db8eaa |
if (result < (snd_pcm_sframes_t)cont) {
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
result = snd_pcm_rewind(rate->gen.slave, result + xfer);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
commit_done:
|
|
Packit Service |
db8eaa |
if (rate->start_pending) {
|
|
Packit Service |
db8eaa |
/* we have pending start-trigger. let's issue it now */
|
|
Packit Service |
db8eaa |
snd_pcm_start(rate->gen.slave);
|
|
Packit Service |
db8eaa |
rate->start_pending = 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_commit_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t appl_offset)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return snd_pcm_rate_commit_area(pcm, rate, appl_offset, pcm->period_size,
|
|
Packit Service |
db8eaa |
rate->gen.slave->period_size);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_grab_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t hw_offset)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset;
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *areas;
|
|
Packit Service |
db8eaa |
const snd_pcm_channel_area_t *slave_areas;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t slave_offset, xfer;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t slave_frames = ULONG_MAX;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t result;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
areas = snd_pcm_mmap_areas(pcm);
|
|
Packit Service |
db8eaa |
if (cont >= pcm->period_size) {
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
if (slave_frames < rate->gen.slave->period_size)
|
|
Packit Service |
db8eaa |
goto __partial;
|
|
Packit Service |
db8eaa |
snd_pcm_rate_read_areas1(pcm, areas, hw_offset,
|
|
Packit Service |
db8eaa |
slave_areas, slave_offset);
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, rate->gen.slave->period_size);
|
|
Packit Service |
db8eaa |
if (result < (snd_pcm_sframes_t)rate->gen.slave->period_size) {
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
result = snd_pcm_rewind(rate->gen.slave, result);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
/* ok, grab first fragment */
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
__partial:
|
|
Packit Service |
45dc4a |
xfer = 0;
|
|
Packit Service |
db8eaa |
cont = slave_frames;
|
|
Packit Service |
db8eaa |
if (cont > rate->gen.slave->period_size)
|
|
Packit Service |
db8eaa |
cont = rate->gen.slave->period_size;
|
|
Packit Service |
db8eaa |
snd_pcm_areas_copy(rate->sareas, 0,
|
|
Packit Service |
db8eaa |
slave_areas, slave_offset,
|
|
Packit Service |
db8eaa |
pcm->channels, cont,
|
|
Packit Service |
db8eaa |
rate->gen.slave->format);
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont);
|
|
Packit Service |
db8eaa |
if (result < (snd_pcm_sframes_t)cont) {
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
result = snd_pcm_rewind(rate->gen.slave, result);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
xfer = cont;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (xfer == rate->gen.slave->period_size)
|
|
Packit Service |
db8eaa |
goto __transfer;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* grab second fragment */
|
|
Packit Service |
db8eaa |
cont = rate->gen.slave->period_size - cont;
|
|
Packit Service |
db8eaa |
slave_frames = cont;
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
#if 0
|
|
Packit Service |
db8eaa |
if (slave_offset) {
|
|
Packit Service |
db8eaa |
SNDERR("non-zero slave_offset %ld", slave_offset);
|
|
Packit Service |
db8eaa |
return -EIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
snd_pcm_areas_copy(rate->sareas, xfer,
|
|
Packit Service |
db8eaa |
slave_areas, slave_offset,
|
|
Packit Service |
db8eaa |
pcm->channels, cont,
|
|
Packit Service |
db8eaa |
rate->gen.slave->format);
|
|
Packit Service |
db8eaa |
result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont);
|
|
Packit Service |
db8eaa |
if (result < (snd_pcm_sframes_t)cont) {
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
result = snd_pcm_rewind(rate->gen.slave, result + xfer);
|
|
Packit Service |
db8eaa |
if (result < 0)
|
|
Packit Service |
db8eaa |
return result;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
__transfer:
|
|
Packit Service |
db8eaa |
cont = pcm->buffer_size - hw_offset;
|
|
Packit Service |
db8eaa |
if (cont >= pcm->period_size) {
|
|
Packit Service |
db8eaa |
snd_pcm_rate_read_areas1(pcm, areas, hw_offset,
|
|
Packit Service |
db8eaa |
rate->sareas, 0);
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
snd_pcm_rate_read_areas1(pcm,
|
|
Packit Service |
db8eaa |
rate->pareas, 0,
|
|
Packit Service |
db8eaa |
rate->sareas, 0);
|
|
Packit Service |
db8eaa |
snd_pcm_areas_copy(areas, hw_offset,
|
|
Packit Service |
db8eaa |
rate->pareas, 0,
|
|
Packit Service |
db8eaa |
pcm->channels, cont,
|
|
Packit Service |
db8eaa |
pcm->format);
|
|
Packit Service |
db8eaa |
snd_pcm_areas_copy(areas, 0,
|
|
Packit Service |
db8eaa |
rate->pareas, cont,
|
|
Packit Service |
db8eaa |
pcm->channels, pcm->period_size - cont,
|
|
Packit Service |
db8eaa |
pcm->format);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_sync_playback_area(snd_pcm_t *pcm, snd_pcm_uframes_t appl_ptr)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_t *slave = rate->gen.slave;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t xfer;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t slave_size;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
slave_size = snd_pcm_avail_update(slave);
|
|
Packit Service |
db8eaa |
if (slave_size < 0)
|
|
Packit Service |
db8eaa |
return slave_size;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
45dc4a |
if (appl_ptr < rate->last_commit_ptr)
|
|
Packit Service |
45dc4a |
xfer = appl_ptr - rate->last_commit_ptr + pcm->boundary;
|
|
Packit Service |
45dc4a |
else
|
|
Packit Service |
45dc4a |
xfer = appl_ptr - rate->last_commit_ptr;
|
|
Packit Service |
db8eaa |
while (xfer >= pcm->period_size &&
|
|
Packit Service |
db8eaa |
(snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) {
|
|
Packit Service |
db8eaa |
err = snd_pcm_rate_commit_next_period(pcm, rate->last_commit_ptr % pcm->buffer_size);
|
|
Packit Service |
db8eaa |
if (err == 0)
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
xfer -= pcm->period_size;
|
|
Packit Service |
db8eaa |
slave_size -= rate->gen.slave->period_size;
|
|
Packit Service |
db8eaa |
rate->last_commit_ptr += pcm->period_size;
|
|
Packit Service |
db8eaa |
if (rate->last_commit_ptr >= pcm->boundary)
|
|
Packit Service |
db8eaa |
rate->last_commit_ptr = 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_pcm_sframes_t snd_pcm_rate_mmap_commit(snd_pcm_t *pcm,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t size)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (size == 0)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit Service |
db8eaa |
err = snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr + size);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
snd_pcm_mmap_appl_forward(pcm, size);
|
|
Packit Service |
db8eaa |
return size;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
45dc4a |
static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_t *slave = rate->gen.slave;
|
|
Packit Service |
45dc4a |
snd_pcm_sframes_t slave_size;
|
|
Packit Service |
45dc4a |
|
|
Packit Service |
45dc4a |
slave_size = snd_pcm_avail_update(slave);
|
|
Packit Service |
45dc4a |
if (slave_size < 0)
|
|
Packit Service |
45dc4a |
return slave_size;
|
|
Packit Service |
45dc4a |
|
|
Packit Service |
45dc4a |
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
|
|
Packit Service |
45dc4a |
goto _capture;
|
|
Packit Service |
45dc4a |
snd_pcm_rate_sync_hwptr(pcm);
|
|
Packit Service |
45dc4a |
snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr);
|
|
Packit Service |
45dc4a |
return snd_pcm_mmap_avail(pcm);
|
|
Packit Service |
45dc4a |
_capture: {
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t xfer, hw_offset, size;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
xfer = snd_pcm_mmap_capture_avail(pcm);
|
|
Packit Service |
db8eaa |
size = pcm->buffer_size - xfer;
|
|
Packit Service |
db8eaa |
hw_offset = snd_pcm_mmap_hw_offset(pcm);
|
|
Packit Service |
db8eaa |
while (size >= pcm->period_size &&
|
|
Packit Service |
45dc4a |
(snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) {
|
|
Packit Service |
db8eaa |
int err = snd_pcm_rate_grab_next_period(pcm, hw_offset);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
if (err == 0)
|
|
Packit Service |
db8eaa |
return (snd_pcm_sframes_t)xfer;
|
|
Packit Service |
db8eaa |
xfer += pcm->period_size;
|
|
Packit Service |
db8eaa |
size -= pcm->period_size;
|
|
Packit Service |
45dc4a |
slave_size -= rate->gen.slave->period_size;
|
|
Packit Service |
db8eaa |
hw_offset += pcm->period_size;
|
|
Packit Service |
db8eaa |
hw_offset %= pcm->buffer_size;
|
|
Packit Service |
db8eaa |
snd_pcm_mmap_hw_forward(pcm, pcm->period_size);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return (snd_pcm_sframes_t)xfer;
|
|
Packit Service |
45dc4a |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_htimestamp(snd_pcm_t *pcm,
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t *avail,
|
|
Packit Service |
db8eaa |
snd_htimestamp_t *tstamp)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t avail1;
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t tmp;
|
|
Packit Service |
db8eaa |
int ok = 0, err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
while (1) {
|
|
Packit Service |
db8eaa |
/* the position is from this plugin itself */
|
|
Packit Service |
db8eaa |
avail1 = snd_pcm_avail_update(pcm);
|
|
Packit Service |
db8eaa |
if (avail1 < 0)
|
|
Packit Service |
db8eaa |
return avail1;
|
|
Packit Service |
db8eaa |
if (ok && (snd_pcm_uframes_t)avail1 == *avail)
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
*avail = avail1;
|
|
Packit Service |
db8eaa |
/* timestamp is taken from the slave PCM */
|
|
Packit Service |
db8eaa |
err = snd_pcm_htimestamp(rate->gen.slave, &tmp, tstamp);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
ok = 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit Service |
db8eaa |
/* Try to sync as much as possible */
|
|
Packit Service |
db8eaa |
snd_pcm_rate_hwsync(pcm);
|
|
Packit Service |
db8eaa |
snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return snd_pcm_poll_descriptors_revents(rate->gen.slave, pfds, nfds, revents);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* locking */
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_drain(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit Service |
db8eaa |
/* commit the remaining fraction (if any) */
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t size, ofs, saved_avail_min;
|
|
Packit Service |
db8eaa |
snd_pcm_sw_params_t sw_params;
|
|
Packit Service |
db8eaa |
int commit_err = 0;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
__snd_pcm_lock(pcm);
|
|
Packit Service |
db8eaa |
/* temporarily set avail_min to one */
|
|
Packit Service |
db8eaa |
sw_params = rate->sw_params;
|
|
Packit Service |
db8eaa |
saved_avail_min = sw_params.avail_min;
|
|
Packit Service |
db8eaa |
sw_params.avail_min = 1;
|
|
Packit Service |
db8eaa |
snd_pcm_sw_params(rate->gen.slave, &sw_params);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
45dc4a |
size = rate->appl_ptr - rate->last_commit_ptr;
|
|
Packit Service |
45dc4a |
if (size > pcm->boundary)
|
|
Packit Service |
45dc4a |
size -= pcm->boundary;
|
|
Packit Service |
db8eaa |
ofs = rate->last_commit_ptr % pcm->buffer_size;
|
|
Packit Service |
db8eaa |
while (size > 0) {
|
|
Packit Service |
db8eaa |
snd_pcm_uframes_t psize, spsize;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = __snd_pcm_wait_in_lock(rate->gen.slave, -1);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
if (size > pcm->period_size) {
|
|
Packit Service |
db8eaa |
psize = pcm->period_size;
|
|
Packit Service |
db8eaa |
spsize = rate->gen.slave->period_size;
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
psize = size;
|
|
Packit Service |
db8eaa |
spsize = rate->ops.output_frames(rate->obj, size);
|
|
Packit Service |
db8eaa |
if (! spsize)
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
commit_err = snd_pcm_rate_commit_area(pcm, rate, ofs,
|
|
Packit Service |
db8eaa |
psize, spsize);
|
|
Packit Service |
db8eaa |
if (commit_err == 1) {
|
|
Packit Service |
db8eaa |
rate->last_commit_ptr += psize;
|
|
Packit Service |
db8eaa |
if (rate->last_commit_ptr >= pcm->boundary)
|
|
Packit Service |
db8eaa |
rate->last_commit_ptr = 0;
|
|
Packit Service |
db8eaa |
} else if (commit_err == 0) {
|
|
Packit Service |
db8eaa |
if (pcm->mode & SND_PCM_NONBLOCK) {
|
|
Packit Service |
db8eaa |
commit_err = -EAGAIN;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
} else
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
ofs = (ofs + psize) % pcm->buffer_size;
|
|
Packit Service |
db8eaa |
size -= psize;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
sw_params.avail_min = saved_avail_min;
|
|
Packit Service |
db8eaa |
snd_pcm_sw_params(rate->gen.slave, &sw_params);
|
|
Packit Service |
db8eaa |
__snd_pcm_unlock(pcm);
|
|
Packit Service |
db8eaa |
if (commit_err < 0)
|
|
Packit Service |
db8eaa |
return commit_err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return snd_pcm_drain(rate->gen.slave);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_pcm_state_t snd_pcm_rate_state(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
if (rate->start_pending) /* pseudo-state */
|
|
Packit Service |
db8eaa |
return SND_PCM_STATE_RUNNING;
|
|
Packit Service |
db8eaa |
return snd_pcm_state(rate->gen.slave);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_start(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t avail;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
|
|
Packit Service |
db8eaa |
return snd_pcm_start(rate->gen.slave);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (snd_pcm_state(rate->gen.slave) != SND_PCM_STATE_PREPARED)
|
|
Packit Service |
db8eaa |
return -EBADFD;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
gettimestamp(&rate->trigger_tstamp, pcm->tstamp_type);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
avail = snd_pcm_mmap_playback_hw_avail(rate->gen.slave);
|
|
Packit Service |
db8eaa |
if (avail < 0) /* can't happen on healthy drivers */
|
|
Packit Service |
db8eaa |
return -EBADFD;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (avail == 0) {
|
|
Packit Service |
db8eaa |
/* postpone the trigger since we have no data committed yet */
|
|
Packit Service |
db8eaa |
rate->start_pending = 1;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
rate->start_pending = 0;
|
|
Packit Service |
db8eaa |
return snd_pcm_start(rate->gen.slave);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = snd_pcm_status(rate->gen.slave, status);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit Service |
db8eaa |
if (rate->start_pending)
|
|
Packit Service |
db8eaa |
status->state = SND_PCM_STATE_RUNNING;
|
|
Packit Service |
db8eaa |
status->trigger_tstamp = rate->trigger_tstamp;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
snd_pcm_rate_sync_hwptr0(pcm, status->hw_ptr);
|
|
Packit Service |
db8eaa |
status->appl_ptr = *pcm->appl.ptr;
|
|
Packit Service |
db8eaa |
status->hw_ptr = *pcm->hw.ptr;
|
|
Packit Service |
db8eaa |
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
Packit Service |
db8eaa |
status->delay = rate->ops.input_frames(rate->obj, status->delay)
|
|
Packit Service |
db8eaa |
+ snd_pcm_rate_playback_internal_delay(pcm);
|
|
Packit Service |
db8eaa |
status->avail = snd_pcm_mmap_playback_avail(pcm);
|
|
Packit Service |
db8eaa |
status->avail_max = rate->ops.input_frames(rate->obj, status->avail_max);
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
45dc4a |
/* FIXME: Maybe possible to somthing similar to
|
|
Packit Service |
45dc4a |
* snd_pcm_rate_playback_internal_delay()
|
|
Packit Service |
45dc4a |
* for the capture case.
|
|
Packit Service |
45dc4a |
*/
|
|
Packit Service |
db8eaa |
status->delay = rate->ops.output_frames(rate->obj, status->delay)
|
|
Packit Service |
45dc4a |
+ snd_pcm_mmap_capture_hw_avail(pcm);
|
|
Packit Service |
db8eaa |
status->avail = snd_pcm_mmap_capture_avail(pcm);
|
|
Packit Service |
db8eaa |
status->avail_max = rate->ops.output_frames(rate->obj, status->avail_max);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void snd_pcm_rate_dump(snd_pcm_t *pcm, snd_output_t *out)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
if (rate->sformat == SND_PCM_FORMAT_UNKNOWN)
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "Rate conversion PCM (%d)\n",
|
|
Packit Service |
db8eaa |
rate->srate);
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "Rate conversion PCM (%d, sformat=%s)\n",
|
|
Packit Service |
db8eaa |
rate->srate,
|
|
Packit Service |
db8eaa |
snd_pcm_format_name(rate->sformat));
|
|
Packit Service |
db8eaa |
if (rate->ops.dump)
|
|
Packit Service |
db8eaa |
rate->ops.dump(rate->obj, out);
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "Protocol version: %x\n", rate->plugin_version);
|
|
Packit Service |
db8eaa |
if (pcm->setup) {
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "Its setup is:\n");
|
|
Packit Service |
db8eaa |
snd_pcm_dump_setup(pcm, out);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
snd_output_printf(out, "Slave: ");
|
|
Packit Service |
db8eaa |
snd_pcm_dump(rate->gen.slave, out);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_pcm_rate_close(snd_pcm_t *pcm)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate = pcm->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (rate->ops.close)
|
|
Packit Service |
db8eaa |
rate->ops.close(rate->obj);
|
|
Packit Service |
db8eaa |
if (rate->open_func)
|
|
Packit Service |
db8eaa |
snd_dlobj_cache_put(rate->open_func);
|
|
Packit Service |
db8eaa |
return snd_pcm_generic_close(pcm);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static const snd_pcm_fast_ops_t snd_pcm_rate_fast_ops = {
|
|
Packit Service |
db8eaa |
.status = snd_pcm_rate_status,
|
|
Packit Service |
db8eaa |
.state = snd_pcm_rate_state,
|
|
Packit Service |
db8eaa |
.hwsync = snd_pcm_rate_hwsync,
|
|
Packit Service |
db8eaa |
.delay = snd_pcm_rate_delay,
|
|
Packit Service |
db8eaa |
.prepare = snd_pcm_rate_prepare,
|
|
Packit Service |
db8eaa |
.reset = snd_pcm_rate_reset,
|
|
Packit Service |
db8eaa |
.start = snd_pcm_rate_start,
|
|
Packit Service |
db8eaa |
.drop = snd_pcm_generic_drop,
|
|
Packit Service |
db8eaa |
.drain = snd_pcm_rate_drain,
|
|
Packit Service |
db8eaa |
.pause = snd_pcm_generic_pause,
|
|
Packit Service |
db8eaa |
.rewindable = snd_pcm_rate_rewindable,
|
|
Packit Service |
db8eaa |
.rewind = snd_pcm_rate_rewind,
|
|
Packit Service |
db8eaa |
.forwardable = snd_pcm_rate_forwardable,
|
|
Packit Service |
db8eaa |
.forward = snd_pcm_rate_forward,
|
|
Packit Service |
db8eaa |
.resume = snd_pcm_generic_resume,
|
|
Packit Service |
db8eaa |
.writei = snd_pcm_mmap_writei,
|
|
Packit Service |
db8eaa |
.writen = snd_pcm_mmap_writen,
|
|
Packit Service |
db8eaa |
.readi = snd_pcm_mmap_readi,
|
|
Packit Service |
db8eaa |
.readn = snd_pcm_mmap_readn,
|
|
Packit Service |
db8eaa |
.avail_update = snd_pcm_rate_avail_update,
|
|
Packit Service |
db8eaa |
.mmap_commit = snd_pcm_rate_mmap_commit,
|
|
Packit Service |
db8eaa |
.htimestamp = snd_pcm_rate_htimestamp,
|
|
Packit Service |
db8eaa |
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
|
|
Packit Service |
db8eaa |
.poll_descriptors = snd_pcm_generic_poll_descriptors,
|
|
Packit Service |
db8eaa |
.poll_revents = snd_pcm_rate_poll_revents,
|
|
Packit Service |
db8eaa |
.may_wait_for_avail_min = snd_pcm_plugin_may_wait_for_avail_min,
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static const snd_pcm_ops_t snd_pcm_rate_ops = {
|
|
Packit Service |
db8eaa |
.close = snd_pcm_rate_close,
|
|
Packit Service |
db8eaa |
.info = snd_pcm_generic_info,
|
|
Packit Service |
db8eaa |
.hw_refine = snd_pcm_rate_hw_refine,
|
|
Packit Service |
db8eaa |
.hw_params = snd_pcm_rate_hw_params,
|
|
Packit Service |
db8eaa |
.hw_free = snd_pcm_rate_hw_free,
|
|
Packit Service |
db8eaa |
.sw_params = snd_pcm_rate_sw_params,
|
|
Packit Service |
db8eaa |
.channel_info = snd_pcm_generic_channel_info,
|
|
Packit Service |
db8eaa |
.dump = snd_pcm_rate_dump,
|
|
Packit Service |
db8eaa |
.nonblock = snd_pcm_generic_nonblock,
|
|
Packit Service |
db8eaa |
.async = snd_pcm_generic_async,
|
|
Packit Service |
db8eaa |
.mmap = snd_pcm_generic_mmap,
|
|
Packit Service |
db8eaa |
.munmap = snd_pcm_generic_munmap,
|
|
Packit Service |
db8eaa |
.query_chmaps = snd_pcm_generic_query_chmaps,
|
|
Packit Service |
db8eaa |
.get_chmap = snd_pcm_generic_get_chmap,
|
|
Packit Service |
db8eaa |
.set_chmap = snd_pcm_generic_set_chmap,
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Get a default converter string
|
|
Packit Service |
db8eaa |
* \param root Root configuration node
|
|
Packit Service |
db8eaa |
* \retval A const config item if found, or NULL
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
const snd_config_t *snd_pcm_rate_get_default_converter(snd_config_t *root)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_config_t *n;
|
|
Packit Service |
db8eaa |
/* look for default definition */
|
|
Packit Service |
db8eaa |
if (snd_config_search(root, "defaults.pcm.rate_converter", &n) >= 0)
|
|
Packit Service |
db8eaa |
return n;
|
|
Packit Service |
db8eaa |
return NULL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#ifdef PIC
|
|
Packit Service |
db8eaa |
static int is_builtin_plugin(const char *type)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return strcmp(type, "linear") == 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static const char *const default_rate_plugins[] = {
|
|
Packit Service |
db8eaa |
"speexrate", "linear", NULL
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int rate_open_func(snd_pcm_rate_t *rate, const char *type, const snd_config_t *converter_conf, int verbose)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
char open_name[64], open_conf_name[64], lib_name[64], *lib = NULL;
|
|
Packit Service |
db8eaa |
snd_pcm_rate_open_func_t open_func;
|
|
Packit Service |
db8eaa |
snd_pcm_rate_open_conf_func_t open_conf_func;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
snprintf(open_name, sizeof(open_name), "_snd_pcm_rate_%s_open", type);
|
|
Packit Service |
db8eaa |
snprintf(open_conf_name, sizeof(open_conf_name), "_snd_pcm_rate_%s_open_conf", type);
|
|
Packit Service |
db8eaa |
if (!is_builtin_plugin(type)) {
|
|
Packit Service |
db8eaa |
snprintf(lib_name, sizeof(lib_name),
|
|
Packit Service |
db8eaa |
"libasound_module_rate_%s.so", type);
|
|
Packit Service |
db8eaa |
lib = lib_name;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
rate->rate_min = SND_PCM_PLUGIN_RATE_MIN;
|
|
Packit Service |
db8eaa |
rate->rate_max = SND_PCM_PLUGIN_RATE_MAX;
|
|
Packit Service |
db8eaa |
rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
open_conf_func = snd_dlobj_cache_get(lib, open_conf_name, NULL, verbose && converter_conf != NULL);
|
|
Packit Service |
db8eaa |
if (open_conf_func) {
|
|
Packit Service |
db8eaa |
err = open_conf_func(SND_PCM_RATE_PLUGIN_VERSION,
|
|
Packit Service |
db8eaa |
&rate->obj, &rate->ops, converter_conf);
|
|
Packit Service |
db8eaa |
if (!err) {
|
|
Packit Service |
db8eaa |
rate->plugin_version = rate->ops.version;
|
|
Packit Service |
db8eaa |
if (rate->ops.get_supported_rates)
|
|
Packit Service |
db8eaa |
rate->ops.get_supported_rates(rate->obj,
|
|
Packit Service |
db8eaa |
&rate->rate_min,
|
|
Packit Service |
db8eaa |
&rate->rate_max);
|
|
Packit Service |
db8eaa |
rate->open_func = open_conf_func;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
snd_dlobj_cache_put(open_conf_func);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
open_func = snd_dlobj_cache_get(lib, open_name, NULL, verbose);
|
|
Packit Service |
db8eaa |
if (!open_func)
|
|
Packit Service |
db8eaa |
return -ENOENT;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
rate->open_func = open_func;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops);
|
|
Packit Service |
db8eaa |
if (!err) {
|
|
Packit Service |
db8eaa |
rate->plugin_version = rate->ops.version;
|
|
Packit Service |
db8eaa |
if (rate->ops.get_supported_rates)
|
|
Packit Service |
db8eaa |
rate->ops.get_supported_rates(rate->obj,
|
|
Packit Service |
db8eaa |
&rate->rate_min,
|
|
Packit Service |
db8eaa |
&rate->rate_max);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* try to open with the old protocol version */
|
|
Packit Service |
db8eaa |
rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION_OLD;
|
|
Packit Service |
db8eaa |
err = open_func(SND_PCM_RATE_PLUGIN_VERSION_OLD,
|
|
Packit Service |
db8eaa |
&rate->obj, &rate->ops);
|
|
Packit Service |
db8eaa |
if (err) {
|
|
Packit Service |
db8eaa |
snd_dlobj_cache_put(open_func);
|
|
Packit Service |
db8eaa |
rate->open_func = NULL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/*
|
|
Packit Service |
db8eaa |
* If the conf is an array of alternatives then the id of
|
|
Packit Service |
db8eaa |
* the first element will be "0" (or maybe NULL). Otherwise assume it is
|
|
Packit Service |
db8eaa |
* a structure.
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
static int is_string_array(const snd_config_t *conf)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_config_iterator_t i;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
i = snd_config_iterator_first(conf);
|
|
Packit Service |
db8eaa |
if (i && i != snd_config_iterator_end(conf)) {
|
|
Packit Service |
db8eaa |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit Service |
db8eaa |
const char *id;
|
|
Packit Service |
db8eaa |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
if (id && strcmp(id, "0") != 0)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Creates a new rate PCM
|
|
Packit Service |
db8eaa |
* \param pcmp Returns created PCM handle
|
|
Packit Service |
db8eaa |
* \param name Name of PCM
|
|
Packit Service |
db8eaa |
* \param sformat Slave format
|
|
Packit Service |
db8eaa |
* \param srate Slave rate
|
|
Packit Service |
db8eaa |
* \param converter SRC type string node
|
|
Packit Service |
db8eaa |
* \param slave Slave PCM handle
|
|
Packit Service |
db8eaa |
* \param close_slave When set, the slave PCM handle is closed with copy PCM
|
|
Packit Service |
db8eaa |
* \retval zero on success otherwise a negative error code
|
|
Packit Service |
db8eaa |
* \warning Using of this function might be dangerous in the sense
|
|
Packit Service |
db8eaa |
* of compatibility reasons. The prototype might be freely
|
|
Packit Service |
db8eaa |
* changed in future.
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name,
|
|
Packit Service |
db8eaa |
snd_pcm_format_t sformat, unsigned int srate,
|
|
Packit Service |
db8eaa |
const snd_config_t *converter,
|
|
Packit Service |
db8eaa |
snd_pcm_t *slave, int close_slave)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_t *pcm;
|
|
Packit Service |
db8eaa |
snd_pcm_rate_t *rate;
|
|
Packit Service |
db8eaa |
const char *type = NULL;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
#ifndef PIC
|
|
Packit Service |
db8eaa |
snd_pcm_rate_open_func_t open_func;
|
|
Packit Service |
db8eaa |
extern int SND_PCM_RATE_PLUGIN_ENTRY(linear) (unsigned int version, void **objp, snd_pcm_rate_ops_t *ops);
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
assert(pcmp && slave);
|
|
Packit Service |
db8eaa |
if (sformat != SND_PCM_FORMAT_UNKNOWN &&
|
|
Packit Service |
db8eaa |
snd_pcm_format_linear(sformat) != 1)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
rate = calloc(1, sizeof(snd_pcm_rate_t));
|
|
Packit Service |
db8eaa |
if (!rate) {
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
rate->gen.slave = slave;
|
|
Packit Service |
db8eaa |
rate->gen.close_slave = close_slave;
|
|
Packit Service |
db8eaa |
rate->srate = srate;
|
|
Packit Service |
db8eaa |
rate->sformat = sformat;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = snd_pcm_new(&pcm, SND_PCM_TYPE_RATE, name, slave->stream, slave->mode);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
free(rate);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#ifdef PIC
|
|
Packit Service |
db8eaa |
err = -ENOENT;
|
|
Packit Service |
db8eaa |
if (!converter) {
|
|
Packit Service |
db8eaa |
const char *const *types;
|
|
Packit Service |
db8eaa |
for (types = default_rate_plugins; *types; types++) {
|
|
Packit Service |
db8eaa |
err = rate_open_func(rate, *types, NULL, 0);
|
|
Packit Service |
db8eaa |
if (!err) {
|
|
Packit Service |
db8eaa |
type = *types;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
} else if (!snd_config_get_string(converter, &type))
|
|
Packit Service |
db8eaa |
err = rate_open_func(rate, type, NULL, 1);
|
|
Packit Service |
db8eaa |
else if (is_string_array(converter)) {
|
|
Packit Service |
db8eaa |
snd_config_iterator_t i, next;
|
|
Packit Service |
db8eaa |
snd_config_for_each(i, next, converter) {
|
|
Packit Service |
db8eaa |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit Service |
db8eaa |
if (snd_config_get_string(n, &type) < 0)
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
err = rate_open_func(rate, type, NULL, 0);
|
|
Packit Service |
db8eaa |
if (!err)
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
} else if (snd_config_get_type(converter) == SND_CONFIG_TYPE_COMPOUND) {
|
|
Packit Service |
db8eaa |
snd_config_iterator_t i, next;
|
|
Packit Service |
db8eaa |
snd_config_for_each(i, next, converter) {
|
|
Packit Service |
db8eaa |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit Service |
db8eaa |
const char *id;
|
|
Packit Service |
db8eaa |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
if (strcmp(id, "name") != 0)
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
snd_config_get_string(n, &type);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (!type) {
|
|
Packit Service |
db8eaa |
SNDERR("No name given for rate converter");
|
|
Packit Service |
db8eaa |
snd_pcm_free(pcm);
|
|
Packit Service |
db8eaa |
free(rate);
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
err = rate_open_func(rate, type, converter, 1);
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
SNDERR("Invalid type for rate converter");
|
|
Packit Service |
db8eaa |
snd_pcm_free(pcm);
|
|
Packit Service |
db8eaa |
free(rate);
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
SNDERR("Cannot find rate converter");
|
|
Packit Service |
db8eaa |
snd_pcm_free(pcm);
|
|
Packit Service |
db8eaa |
free(rate);
|
|
Packit Service |
db8eaa |
return -ENOENT;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
#else
|
|
Packit Service |
db8eaa |
type = "linear";
|
|
Packit Service |
db8eaa |
open_func = SND_PCM_RATE_PLUGIN_ENTRY(linear);
|
|
Packit Service |
db8eaa |
err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
snd_pcm_free(pcm);
|
|
Packit Service |
db8eaa |
free(rate);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (! rate->ops.init || ! (rate->ops.convert || rate->ops.convert_s16) ||
|
|
Packit Service |
db8eaa |
! rate->ops.input_frames || ! rate->ops.output_frames) {
|
|
Packit Service |
db8eaa |
SNDERR("Inproper rate plugin %s initialization", type);
|
|
Packit Service |
db8eaa |
snd_pcm_free(pcm);
|
|
Packit Service |
db8eaa |
free(rate);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
pcm->ops = &snd_pcm_rate_ops;
|
|
Packit Service |
db8eaa |
pcm->fast_ops = &snd_pcm_rate_fast_ops;
|
|
Packit Service |
db8eaa |
pcm->private_data = rate;
|
|
Packit Service |
db8eaa |
pcm->poll_fd = slave->poll_fd;
|
|
Packit Service |
db8eaa |
pcm->poll_events = slave->poll_events;
|
|
Packit Service |
db8eaa |
pcm->mmap_rw = 1;
|
|
Packit Service |
db8eaa |
pcm->tstamp_type = slave->tstamp_type;
|
|
Packit Service |
db8eaa |
snd_pcm_set_hw_ptr(pcm, &rate->hw_ptr, -1, 0);
|
|
Packit Service |
db8eaa |
snd_pcm_set_appl_ptr(pcm, &rate->appl_ptr, -1, 0);
|
|
Packit Service |
db8eaa |
*pcmp = pcm;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/*! \page pcm_plugins
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
\section pcm_plugins_rate Plugin: Rate
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
This plugin converts a stream rate. The input and output formats must be linear.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
\code
|
|
Packit Service |
db8eaa |
pcm.name {
|
|
Packit Service |
db8eaa |
type rate # Rate PCM
|
|
Packit Service |
db8eaa |
slave STR # Slave name
|
|
Packit Service |
db8eaa |
# or
|
|
Packit Service |
db8eaa |
slave { # Slave definition
|
|
Packit Service |
db8eaa |
pcm STR # Slave PCM name
|
|
Packit Service |
db8eaa |
# or
|
|
Packit Service |
db8eaa |
pcm { } # Slave PCM definition
|
|
Packit Service |
db8eaa |
rate INT # Slave rate
|
|
Packit Service |
db8eaa |
[format STR] # Slave format
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
converter STR # optional
|
|
Packit Service |
db8eaa |
# or
|
|
Packit Service |
db8eaa |
converter [ STR1 STR2 ... ] # optional
|
|
Packit Service |
db8eaa |
# Converter type, default is taken from
|
|
Packit Service |
db8eaa |
# defaults.pcm.rate_converter
|
|
Packit Service |
db8eaa |
# or
|
|
Packit Service |
db8eaa |
converter { # optional
|
|
Packit Service |
db8eaa |
name STR # Convertor type
|
|
Packit Service |
db8eaa |
xxx yyy # optional convertor-specific configuration
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
\endcode
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
\subsection pcm_plugins_rate_funcref Function reference
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
snd_pcm_rate_open()
|
|
Packit Service |
db8eaa |
_snd_pcm_rate_open()
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Creates a new rate PCM
|
|
Packit Service |
db8eaa |
* \param pcmp Returns created PCM handle
|
|
Packit Service |
db8eaa |
* \param name Name of PCM
|
|
Packit Service |
db8eaa |
* \param root Root configuration node
|
|
Packit Service |
db8eaa |
* \param conf Configuration node with rate PCM description
|
|
Packit Service |
db8eaa |
* \param stream Stream type
|
|
Packit Service |
db8eaa |
* \param mode Stream mode
|
|
Packit Service |
db8eaa |
* \retval zero on success otherwise a negative error code
|
|
Packit Service |
db8eaa |
* \warning Using of this function might be dangerous in the sense
|
|
Packit Service |
db8eaa |
* of compatibility reasons. The prototype might be freely
|
|
Packit Service |
db8eaa |
* changed in future.
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
int _snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name,
|
|
Packit Service |
db8eaa |
snd_config_t *root, snd_config_t *conf,
|
|
Packit Service |
db8eaa |
snd_pcm_stream_t stream, int mode)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_config_iterator_t i, next;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
snd_pcm_t *spcm;
|
|
Packit Service |
db8eaa |
snd_config_t *slave = NULL, *sconf;
|
|
Packit Service |
db8eaa |
snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN;
|
|
Packit Service |
db8eaa |
int srate = -1;
|
|
Packit Service |
db8eaa |
const snd_config_t *converter = NULL;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
snd_config_for_each(i, next, conf) {
|
|
Packit Service |
db8eaa |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit Service |
db8eaa |
const char *id;
|
|
Packit Service |
db8eaa |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
if (snd_pcm_conf_generic_id(id))
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
if (strcmp(id, "slave") == 0) {
|
|
Packit Service |
db8eaa |
slave = n;
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (strcmp(id, "converter") == 0) {
|
|
Packit Service |
db8eaa |
converter = n;
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
SNDERR("Unknown field %s", id);
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (!slave) {
|
|
Packit Service |
db8eaa |
SNDERR("slave is not defined");
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = snd_pcm_slave_conf(root, slave, &sconf, 2,
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARAM_FORMAT, 0, &sformat,
|
|
Packit Service |
db8eaa |
SND_PCM_HW_PARAM_RATE, SCONF_MANDATORY, &srate);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
if (sformat != SND_PCM_FORMAT_UNKNOWN &&
|
|
Packit Service |
db8eaa |
snd_pcm_format_linear(sformat) != 1) {
|
|
Packit Service |
db8eaa |
snd_config_delete(sconf);
|
|
Packit Service |
db8eaa |
SNDERR("slave format is not linear");
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
|
|
Packit Service |
db8eaa |
snd_config_delete(sconf);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = snd_pcm_rate_open(pcmp, name, sformat, (unsigned int) srate,
|
|
Packit Service |
db8eaa |
converter, spcm, 1);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
snd_pcm_close(spcm);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
#ifndef DOC_HIDDEN
|
|
Packit Service |
db8eaa |
SND_DLSYM_BUILD_VERSION(_snd_pcm_rate_open, SND_PCM_DLSYM_VERSION);
|
|
Packit Service |
db8eaa |
#endif
|