Home | History | Annotate | Download | only in pcm
      1 /**
      2  * \file pcm/pcm_rate.c
      3  * \ingroup PCM_Plugins
      4  * \brief PCM Rate Plugin Interface
      5  * \author Abramo Bagnara <abramo (at) alsa-project.org>
      6  * \author Jaroslav Kysela <perex (at) perex.cz>
      7  * \date 2000-2004
      8  */
      9 /*
     10  *  PCM - Rate conversion
     11  *  Copyright (c) 2000 by Abramo Bagnara <abramo (at) alsa-project.org>
     12  *                2004 by Jaroslav Kysela <perex (at) perex.cz>
     13  *
     14  *
     15  *   This library is free software; you can redistribute it and/or modify
     16  *   it under the terms of the GNU Lesser General Public License as
     17  *   published by the Free Software Foundation; either version 2.1 of
     18  *   the License, or (at your option) any later version.
     19  *
     20  *   This program is distributed in the hope that it will be useful,
     21  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     22  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     23  *   GNU Lesser General Public License for more details.
     24  *
     25  *   You should have received a copy of the GNU Lesser General Public
     26  *   License along with this library; if not, write to the Free Software
     27  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     28  *
     29  */
     30 #include <inttypes.h>
     31 #include <byteswap.h>
     32 #include "pcm_local.h"
     33 #include "pcm_plugin.h"
     34 #include "pcm_rate.h"
     35 #include "iatomic.h"
     36 
     37 #include "plugin_ops.h"
     38 
     39 #if 0
     40 #define DEBUG_REFINE
     41 #endif
     42 
     43 #ifndef PIC
     44 /* entry for static linking */
     45 const char *_snd_module_pcm_rate = "";
     46 #endif
     47 
     48 #ifndef DOC_HIDDEN
     49 
     50 typedef struct _snd_pcm_rate snd_pcm_rate_t;
     51 
     52 struct _snd_pcm_rate {
     53 	snd_pcm_generic_t gen;
     54 	snd_atomic_write_t watom;
     55 	snd_pcm_uframes_t appl_ptr, hw_ptr;
     56 	snd_pcm_uframes_t last_commit_ptr;
     57 	snd_pcm_uframes_t orig_avail_min;
     58 	snd_pcm_sw_params_t sw_params;
     59 	snd_pcm_format_t sformat;
     60 	unsigned int srate;
     61 	snd_pcm_channel_area_t *pareas;	/* areas for splitted period (rate pcm) */
     62 	snd_pcm_channel_area_t *sareas;	/* areas for splitted period (slave pcm) */
     63 	snd_pcm_rate_info_t info;
     64 	void *obj;
     65 	snd_pcm_rate_ops_t ops;
     66 	unsigned int get_idx;
     67 	unsigned int put_idx;
     68 	int16_t *src_buf;
     69 	int16_t *dst_buf;
     70 	int start_pending; /* start is triggered but not commited to slave */
     71 	snd_htimestamp_t trigger_tstamp;
     72 };
     73 
     74 #endif /* DOC_HIDDEN */
     75 
     76 static int snd_pcm_rate_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
     77 {
     78 	int err;
     79 	snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
     80 	snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR };
     81 	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
     82 					 &access_mask);
     83 	if (err < 0)
     84 		return err;
     85 	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT,
     86 					 &format_mask);
     87 	if (err < 0)
     88 		return err;
     89 	err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD);
     90 	if (err < 0)
     91 		return err;
     92 	err = _snd_pcm_hw_param_set_min(params,
     93 					SND_PCM_HW_PARAM_RATE, SND_PCM_PLUGIN_RATE_MIN, 0);
     94 	if (err < 0)
     95 		return err;
     96 	err = _snd_pcm_hw_param_set_max(params,
     97 					SND_PCM_HW_PARAM_RATE, SND_PCM_PLUGIN_RATE_MAX, 0);
     98 	if (err < 0)
     99 		return err;
    100 	params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
    101 	return 0;
    102 }
    103 
    104 static int snd_pcm_rate_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
    105 {
    106 	snd_pcm_rate_t *rate = pcm->private_data;
    107 	snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
    108 	_snd_pcm_hw_params_any(sparams);
    109 	_snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
    110 				   &saccess_mask);
    111 	if (rate->sformat != SND_PCM_FORMAT_UNKNOWN) {
    112 		_snd_pcm_hw_params_set_format(sparams, rate->sformat);
    113 		_snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
    114 	}
    115 	_snd_pcm_hw_param_set_minmax(sparams, SND_PCM_HW_PARAM_RATE,
    116 				     rate->srate, 0, rate->srate + 1, -1);
    117 	return 0;
    118 }
    119 
    120 static int snd_pcm_rate_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
    121 					  snd_pcm_hw_params_t *sparams)
    122 {
    123 	snd_pcm_rate_t *rate = pcm->private_data;
    124 	snd_interval_t t, buffer_size;
    125 	const snd_interval_t *srate, *crate;
    126 	int err;
    127 	unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
    128 			      SND_PCM_HW_PARBIT_PERIOD_TIME |
    129 			      SND_PCM_HW_PARBIT_TICK_TIME);
    130 	if (rate->sformat == SND_PCM_FORMAT_UNKNOWN)
    131 		links |= (SND_PCM_HW_PARBIT_FORMAT |
    132 			  SND_PCM_HW_PARBIT_SUBFORMAT |
    133 			  SND_PCM_HW_PARBIT_SAMPLE_BITS |
    134 			  SND_PCM_HW_PARBIT_FRAME_BITS);
    135 	snd_interval_copy(&buffer_size, snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE));
    136 	snd_interval_unfloor(&buffer_size);
    137 	crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE);
    138 	srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE);
    139 	snd_interval_muldiv(&buffer_size, srate, crate, &t);
    140 	err = _snd_pcm_hw_param_set_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
    141 	if (err < 0)
    142 		return err;
    143 	err = _snd_pcm_hw_params_refine(sparams, links, params);
    144 	if (err < 0)
    145 		return err;
    146 	return 0;
    147 }
    148 
    149 static int snd_pcm_rate_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
    150 					  snd_pcm_hw_params_t *sparams)
    151 {
    152 	snd_pcm_rate_t *rate = pcm->private_data;
    153 	snd_interval_t t;
    154 #ifdef DEBUG_REFINE
    155 	snd_output_t *out;
    156 #endif
    157 	const snd_interval_t *sbuffer_size, *buffer_size;
    158 	const snd_interval_t *srate, *crate;
    159 	int err;
    160 	unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
    161 			      SND_PCM_HW_PARBIT_PERIOD_TIME |
    162 			      SND_PCM_HW_PARBIT_TICK_TIME);
    163 	if (rate->sformat == SND_PCM_FORMAT_UNKNOWN)
    164 		links |= (SND_PCM_HW_PARBIT_FORMAT |
    165 			  SND_PCM_HW_PARBIT_SUBFORMAT |
    166 			  SND_PCM_HW_PARBIT_SAMPLE_BITS |
    167 			  SND_PCM_HW_PARBIT_FRAME_BITS);
    168 	sbuffer_size = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE);
    169 	crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE);
    170 	srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE);
    171 	snd_interval_muldiv(sbuffer_size, crate, srate, &t);
    172 	snd_interval_floor(&t);
    173 	err = _snd_pcm_hw_param_set_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
    174 	if (err < 0)
    175 		return err;
    176 	buffer_size = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE);
    177 	/*
    178 	 * this condition probably needs more work:
    179 	 *   in case when the buffer_size is known and we are looking
    180 	 *   for best period_size, we should prefer situation when
    181 	 *   (buffer_size / period_size) * period_size == buffer_size
    182 	 */
    183 	if (snd_interval_single(buffer_size) && buffer_size->integer) {
    184 		snd_interval_t *period_size;
    185 		period_size = (snd_interval_t *)snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE);
    186 		if (!snd_interval_checkempty(period_size) &&
    187 		    period_size->openmin && period_size->openmax &&
    188 		    period_size->min + 1 == period_size->max) {
    189 		    	if ((buffer_size->min / period_size->min) * period_size->min == buffer_size->min) {
    190 		    		snd_interval_set_value(period_size, period_size->min);
    191 		    	} else if ((buffer_size->max / period_size->max) * period_size->max == buffer_size->max) {
    192 		    		snd_interval_set_value(period_size, period_size->max);
    193 		    	}
    194 		}
    195 	}
    196 #ifdef DEBUG_REFINE
    197 	snd_output_stdio_attach(&out, stderr, 0);
    198 	snd_output_printf(out, "REFINE (params):\n");
    199 	snd_pcm_hw_params_dump(params, out);
    200 	snd_output_printf(out, "REFINE (slave params):\n");
    201 	snd_pcm_hw_params_dump(sparams, out);
    202 	snd_output_close(out);
    203 #endif
    204 	err = _snd_pcm_hw_params_refine(params, links, sparams);
    205 #ifdef DEBUG_REFINE
    206 	snd_output_stdio_attach(&out, stderr, 0);
    207 	snd_output_printf(out, "********************\n");
    208 	snd_output_printf(out, "REFINE (params) (%i):\n", err);
    209 	snd_pcm_hw_params_dump(params, out);
    210 	snd_output_printf(out, "REFINE (slave params):\n");
    211 	snd_pcm_hw_params_dump(sparams, out);
    212 	snd_output_close(out);
    213 #endif
    214 	if (err < 0)
    215 		return err;
    216 	return 0;
    217 }
    218 
    219 static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm,
    220 				  snd_pcm_hw_params_t *params)
    221 {
    222 	return snd_pcm_hw_refine_slave(pcm, params,
    223 				       snd_pcm_rate_hw_refine_cprepare,
    224 				       snd_pcm_rate_hw_refine_cchange,
    225 				       snd_pcm_rate_hw_refine_sprepare,
    226 				       snd_pcm_rate_hw_refine_schange,
    227 				       snd_pcm_generic_hw_refine);
    228 }
    229 
    230 static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
    231 {
    232 	snd_pcm_rate_t *rate = pcm->private_data;
    233 	snd_pcm_t *slave = rate->gen.slave;
    234 	snd_pcm_rate_side_info_t *sinfo, *cinfo;
    235 	unsigned int channels, cwidth, swidth, chn;
    236 	int err = snd_pcm_hw_params_slave(pcm, params,
    237 					  snd_pcm_rate_hw_refine_cchange,
    238 					  snd_pcm_rate_hw_refine_sprepare,
    239 					  snd_pcm_rate_hw_refine_schange,
    240 					  snd_pcm_generic_hw_params);
    241 	if (err < 0)
    242 		return err;
    243 
    244 	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
    245 		cinfo = &rate->info.in;
    246 		sinfo = &rate->info.out;
    247 	} else {
    248 		sinfo = &rate->info.in;
    249 		cinfo = &rate->info.out;
    250 	}
    251 	err = INTERNAL(snd_pcm_hw_params_get_format)(params, &cinfo->format);
    252 	if (err < 0)
    253 		return err;
    254 	err = INTERNAL(snd_pcm_hw_params_get_rate)(params, &cinfo->rate, 0);
    255 	if (err < 0)
    256 		return err;
    257 	err = INTERNAL(snd_pcm_hw_params_get_period_size)(params, &cinfo->period_size, 0);
    258 	if (err < 0)
    259 		return err;
    260 	err = INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &cinfo->buffer_size);
    261 	if (err < 0)
    262 		return err;
    263 	err = INTERNAL(snd_pcm_hw_params_get_channels)(params, &channels);
    264 	if (err < 0)
    265 		return err;
    266 
    267 	rate->info.channels = channels;
    268 	sinfo->format = slave->format;
    269 	sinfo->rate = slave->rate;
    270 	sinfo->buffer_size = slave->buffer_size;
    271 	sinfo->period_size = slave->period_size;
    272 
    273 	if (CHECK_SANITY(rate->pareas)) {
    274 		SNDMSG("rate plugin already in use");
    275 		return -EBUSY;
    276 	}
    277 	err = rate->ops.init(rate->obj, &rate->info);
    278 	if (err < 0)
    279 		return err;
    280 
    281 	rate->pareas = malloc(2 * channels * sizeof(*rate->pareas));
    282 	if (rate->pareas == NULL)
    283 		goto error;
    284 
    285 	cwidth = snd_pcm_format_physical_width(cinfo->format);
    286 	swidth = snd_pcm_format_physical_width(sinfo->format);
    287 	rate->pareas[0].addr = malloc(((cwidth * channels * cinfo->period_size) / 8) +
    288 				      ((swidth * channels * sinfo->period_size) / 8));
    289 	if (rate->pareas[0].addr == NULL)
    290 		goto error;
    291 
    292 	rate->sareas = rate->pareas + channels;
    293 	rate->sareas[0].addr = (char *)rate->pareas[0].addr + ((cwidth * channels * cinfo->period_size) / 8);
    294 	for (chn = 0; chn < channels; chn++) {
    295 		rate->pareas[chn].addr = rate->pareas[0].addr + (cwidth * chn * cinfo->period_size) / 8;
    296 		rate->pareas[chn].first = 0;
    297 		rate->pareas[chn].step = cwidth;
    298 		rate->sareas[chn].addr = rate->sareas[0].addr + (swidth * chn * sinfo->period_size) / 8;
    299 		rate->sareas[chn].first = 0;
    300 		rate->sareas[chn].step = swidth;
    301 	}
    302 
    303 	if (rate->ops.convert_s16) {
    304 		rate->get_idx = snd_pcm_linear_get_index(rate->info.in.format, SND_PCM_FORMAT_S16);
    305 		rate->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, rate->info.out.format);
    306 		free(rate->src_buf);
    307 		rate->src_buf = malloc(channels * rate->info.in.period_size * 2);
    308 		free(rate->dst_buf);
    309 		rate->dst_buf = malloc(channels * rate->info.out.period_size * 2);
    310 		if (! rate->src_buf || ! rate->dst_buf)
    311 			goto error;
    312 	}
    313 
    314 	return 0;
    315 
    316  error:
    317 	if (rate->pareas) {
    318 		free(rate->pareas[0].addr);
    319 		free(rate->pareas);
    320 		rate->pareas = NULL;
    321 	}
    322 	if (rate->ops.free)
    323 		rate->ops.free(rate->obj);
    324 	return -ENOMEM;
    325 }
    326 
    327 static int snd_pcm_rate_hw_free(snd_pcm_t *pcm)
    328 {
    329 	snd_pcm_rate_t *rate = pcm->private_data;
    330 	if (rate->pareas) {
    331 		free(rate->pareas[0].addr);
    332 		free(rate->pareas);
    333 		rate->pareas = NULL;
    334 		rate->sareas = NULL;
    335 	}
    336 	if (rate->ops.free)
    337 		rate->ops.free(rate->obj);
    338 	free(rate->src_buf);
    339 	free(rate->dst_buf);
    340 	rate->src_buf = rate->dst_buf = NULL;
    341 	return snd_pcm_hw_free(rate->gen.slave);
    342 }
    343 
    344 static void recalc(snd_pcm_t *pcm, snd_pcm_uframes_t *val)
    345 {
    346 	snd_pcm_rate_t *rate = pcm->private_data;
    347 	snd_pcm_t *slave = rate->gen.slave;
    348 	unsigned long div;
    349 
    350 	if (*val == pcm->buffer_size) {
    351 		*val = slave->buffer_size;
    352 	} else {
    353 		div = *val / pcm->period_size;
    354 		if (div * pcm->period_size == *val)
    355 			*val = div * slave->period_size;
    356 		else
    357 			*val = muldiv_near(*val, slave->period_size, pcm->period_size);
    358 	}
    359 }
    360 
    361 static int snd_pcm_rate_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
    362 {
    363 	snd_pcm_rate_t *rate = pcm->private_data;
    364 	snd_pcm_t *slave = rate->gen.slave;
    365 	snd_pcm_sw_params_t *sparams;
    366 	snd_pcm_uframes_t boundary1, boundary2, sboundary;
    367 	int err;
    368 
    369 	sparams = &rate->sw_params;
    370 	err = snd_pcm_sw_params_current(slave, sparams);
    371 	if (err < 0)
    372 		return err;
    373 	sboundary = sparams->boundary;
    374 	*sparams = *params;
    375 	boundary1 = pcm->buffer_size;
    376 	boundary2 = slave->buffer_size;
    377 	while (boundary1 * 2 <= LONG_MAX - pcm->buffer_size &&
    378 	       boundary2 * 2 <= LONG_MAX - slave->buffer_size) {
    379 		boundary1 *= 2;
    380 		boundary2 *= 2;
    381 	}
    382 	params->boundary = boundary1;
    383 	sparams->boundary = sboundary;
    384 
    385 	if (rate->ops.adjust_pitch)
    386 		rate->ops.adjust_pitch(rate->obj, &rate->info);
    387 
    388 	recalc(pcm, &sparams->avail_min);
    389 	rate->orig_avail_min = sparams->avail_min;
    390 	recalc(pcm, &sparams->start_threshold);
    391 	if (sparams->avail_min < 1) sparams->avail_min = 1;
    392 	if (sparams->start_threshold <= slave->buffer_size) {
    393 		if (sparams->start_threshold > (slave->buffer_size / sparams->avail_min) * sparams->avail_min)
    394 			sparams->start_threshold = (slave->buffer_size / sparams->avail_min) * sparams->avail_min;
    395 	}
    396 	if (sparams->stop_threshold >= params->boundary) {
    397 		sparams->stop_threshold = sparams->boundary;
    398 	} else {
    399 		recalc(pcm, &sparams->stop_threshold);
    400 	}
    401 	recalc(pcm, &sparams->silence_threshold);
    402 	if (sparams->silence_size >= params->boundary) {
    403 		sparams->silence_size = sparams->boundary;
    404 	} else {
    405 		recalc(pcm, &sparams->silence_size);
    406 	}
    407 	return snd_pcm_sw_params(slave, sparams);
    408 }
    409 
    410 static int snd_pcm_rate_init(snd_pcm_t *pcm)
    411 {
    412 	snd_pcm_rate_t *rate = pcm->private_data;
    413 
    414 	if (rate->ops.reset)
    415 		rate->ops.reset(rate->obj);
    416 	rate->last_commit_ptr = 0;
    417 	rate->start_pending = 0;
    418 	return 0;
    419 }
    420 
    421 static void convert_to_s16(snd_pcm_rate_t *rate, int16_t *buf,
    422 			   const snd_pcm_channel_area_t *areas,
    423 			   snd_pcm_uframes_t offset, unsigned int frames,
    424 			   unsigned int channels)
    425 {
    426 #ifndef DOC_HIDDEN
    427 #define GET16_LABELS
    428 #include "plugin_ops.h"
    429 #undef GET16_LABELS
    430 #endif /* DOC_HIDDEN */
    431 	void *get = get16_labels[rate->get_idx];
    432 	const char *src;
    433 	int16_t sample;
    434 	const char *srcs[channels];
    435 	int src_step[channels];
    436 	unsigned int c;
    437 
    438 	for (c = 0; c < channels; c++) {
    439 		srcs[c] = snd_pcm_channel_area_addr(areas + c, offset);
    440 		src_step[c] = snd_pcm_channel_area_step(areas + c);
    441 	}
    442 
    443 	while (frames--) {
    444 		for (c = 0; c < channels; c++) {
    445 			src = srcs[c];
    446 			goto *get;
    447 #ifndef DOC_HIDDEN
    448 #define GET16_END after_get
    449 #include "plugin_ops.h"
    450 #undef GET16_END
    451 #endif /* DOC_HIDDEN */
    452 		after_get:
    453 			*buf++ = sample;
    454 			srcs[c] += src_step[c];
    455 		}
    456 	}
    457 }
    458 
    459 static void convert_from_s16(snd_pcm_rate_t *rate, const int16_t *buf,
    460 			     const snd_pcm_channel_area_t *areas,
    461 			     snd_pcm_uframes_t offset, unsigned int frames,
    462 			     unsigned int channels)
    463 {
    464 #ifndef DOC_HIDDEN
    465 #define PUT16_LABELS
    466 #include "plugin_ops.h"
    467 #undef PUT16_LABELS
    468 #endif /* DOC_HIDDEN */
    469 	void *put = put16_labels[rate->put_idx];
    470 	char *dst;
    471 	int16_t sample;
    472 	char *dsts[channels];
    473 	int dst_step[channels];
    474 	unsigned int c;
    475 
    476 	for (c = 0; c < channels; c++) {
    477 		dsts[c] = snd_pcm_channel_area_addr(areas + c, offset);
    478 		dst_step[c] = snd_pcm_channel_area_step(areas + c);
    479 	}
    480 
    481 	while (frames--) {
    482 		for (c = 0; c < channels; c++) {
    483 			dst = dsts[c];
    484 			sample = *buf++;
    485 			goto *put;
    486 #ifndef DOC_HIDDEN
    487 #define PUT16_END after_put
    488 #include "plugin_ops.h"
    489 #undef PUT16_END
    490 #endif /* DOC_HIDDEN */
    491 		after_put:
    492 			dsts[c] += dst_step[c];
    493 		}
    494 	}
    495 }
    496 
    497 static void do_convert(const snd_pcm_channel_area_t *dst_areas,
    498 		       snd_pcm_uframes_t dst_offset, unsigned int dst_frames,
    499 		       const snd_pcm_channel_area_t *src_areas,
    500 		       snd_pcm_uframes_t src_offset, unsigned int src_frames,
    501 		       unsigned int channels,
    502 		       snd_pcm_rate_t *rate)
    503 {
    504 	if (rate->ops.convert_s16) {
    505 		const int16_t *src;
    506 		int16_t *dst;
    507 		if (! rate->src_buf)
    508 			src = src_areas->addr + src_offset * 2 * channels;
    509 		else {
    510 			convert_to_s16(rate, rate->src_buf, src_areas, src_offset,
    511 				       src_frames, channels);
    512 			src = rate->src_buf;
    513 		}
    514 		if (! rate->dst_buf)
    515 			dst = dst_areas->addr + dst_offset * 2 * channels;
    516 		else
    517 			dst = rate->dst_buf;
    518 		rate->ops.convert_s16(rate->obj, dst, dst_frames, src, src_frames);
    519 		if (dst == rate->dst_buf)
    520 			convert_from_s16(rate, rate->dst_buf, dst_areas, dst_offset,
    521 					 dst_frames, channels);
    522 	} else {
    523 		rate->ops.convert(rate->obj, dst_areas, dst_offset, dst_frames,
    524 				   src_areas, src_offset, src_frames);
    525 	}
    526 }
    527 
    528 static inline void
    529 snd_pcm_rate_write_areas1(snd_pcm_t *pcm,
    530 			 const snd_pcm_channel_area_t *areas,
    531 			 snd_pcm_uframes_t offset,
    532 			 const snd_pcm_channel_area_t *slave_areas,
    533 			 snd_pcm_uframes_t slave_offset)
    534 {
    535 	snd_pcm_rate_t *rate = pcm->private_data;
    536 	do_convert(slave_areas, slave_offset, rate->gen.slave->period_size,
    537 		   areas, offset, pcm->period_size,
    538 		   pcm->channels, rate);
    539 }
    540 
    541 static inline void
    542 snd_pcm_rate_read_areas1(snd_pcm_t *pcm,
    543 			 const snd_pcm_channel_area_t *areas,
    544 			 snd_pcm_uframes_t offset,
    545 			 const snd_pcm_channel_area_t *slave_areas,
    546 			 snd_pcm_uframes_t slave_offset)
    547 {
    548 	snd_pcm_rate_t *rate = pcm->private_data;
    549 	do_convert(areas, offset, pcm->period_size,
    550 		   slave_areas, slave_offset, rate->gen.slave->period_size,
    551 		   pcm->channels, rate);
    552 }
    553 
    554 static inline snd_pcm_sframes_t snd_pcm_rate_move_applptr(snd_pcm_t *pcm, snd_pcm_sframes_t frames)
    555 {
    556 	snd_pcm_rate_t *rate = pcm->private_data;
    557 	snd_pcm_uframes_t orig_appl_ptr, appl_ptr = rate->appl_ptr, slave_appl_ptr;
    558 	snd_pcm_sframes_t diff, ndiff;
    559 	snd_pcm_t *slave = rate->gen.slave;
    560 
    561 	orig_appl_ptr = rate->appl_ptr;
    562 	if (frames > 0)
    563 		snd_pcm_mmap_appl_forward(pcm, frames);
    564 	else
    565 		snd_pcm_mmap_appl_backward(pcm, -frames);
    566 	slave_appl_ptr =
    567 		(appl_ptr / pcm->period_size) * rate->gen.slave->period_size;
    568 	diff = slave_appl_ptr - *slave->appl.ptr;
    569 	if (diff < -(snd_pcm_sframes_t)(slave->boundary / 2)) {
    570 		diff = (slave->boundary - *slave->appl.ptr) + slave_appl_ptr;
    571 	} else if (diff > (snd_pcm_sframes_t)(slave->boundary / 2)) {
    572 		diff = -((slave->boundary - slave_appl_ptr) + *slave->appl.ptr);
    573 	}
    574 	if (diff == 0)
    575 		return frames;
    576 	if (diff > 0) {
    577 		ndiff = snd_pcm_forward(rate->gen.slave, diff);
    578 	} else {
    579 		ndiff = snd_pcm_rewind(rate->gen.slave, diff);
    580 	}
    581 	if (ndiff < 0)
    582 		return diff;
    583 	slave_appl_ptr = *slave->appl.ptr;
    584 	rate->appl_ptr =
    585 		(slave_appl_ptr / rate->gen.slave->period_size) * pcm->period_size +
    586 		orig_appl_ptr % pcm->period_size;
    587 	if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
    588 		rate->appl_ptr += rate->ops.input_frames(rate->obj, slave_appl_ptr % rate->gen.slave->period_size);
    589 	else
    590 		rate->appl_ptr += rate->ops.output_frames(rate->obj, slave_appl_ptr % rate->gen.slave->period_size);
    591 
    592 	diff = orig_appl_ptr - rate->appl_ptr;
    593 	if (diff < -(snd_pcm_sframes_t)(slave->boundary / 2)) {
    594 		diff = (slave->boundary - rate->appl_ptr) + orig_appl_ptr;
    595 	} else if (diff > (snd_pcm_sframes_t)(slave->boundary / 2)) {
    596 		diff = -((slave->boundary - orig_appl_ptr) + rate->appl_ptr);
    597 	}
    598 	if (frames < 0)
    599 		diff = -diff;
    600 
    601 	rate->last_commit_ptr = rate->appl_ptr - rate->appl_ptr % pcm->period_size;
    602 
    603 	return diff;
    604 }
    605 
    606 static inline void snd_pcm_rate_sync_hwptr(snd_pcm_t *pcm)
    607 {
    608 	snd_pcm_rate_t *rate = pcm->private_data;
    609 	snd_pcm_uframes_t slave_hw_ptr = *rate->gen.slave->hw.ptr;
    610 
    611 	if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
    612 		return;
    613 	/* FIXME: boundary overlap of slave hw_ptr isn't evaluated here!
    614 	 *        e.g. if slave rate is small...
    615 	 */
    616 	rate->hw_ptr =
    617 		(slave_hw_ptr / rate->gen.slave->period_size) * pcm->period_size +
    618 		rate->ops.input_frames(rate->obj, slave_hw_ptr % rate->gen.slave->period_size);
    619 }
    620 
    621 static int snd_pcm_rate_hwsync(snd_pcm_t *pcm)
    622 {
    623 	snd_pcm_rate_t *rate = pcm->private_data;
    624 	int err = snd_pcm_hwsync(rate->gen.slave);
    625 	if (err < 0)
    626 		return err;
    627 	snd_atomic_write_begin(&rate->watom);
    628 	snd_pcm_rate_sync_hwptr(pcm);
    629 	snd_atomic_write_end(&rate->watom);
    630 	return 0;
    631 }
    632 
    633 static int snd_pcm_rate_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
    634 {
    635 	snd_pcm_rate_hwsync(pcm);
    636 	if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
    637 		*delayp = snd_pcm_mmap_playback_hw_avail(pcm);
    638 	else
    639 		*delayp = snd_pcm_mmap_capture_hw_avail(pcm);
    640 	return 0;
    641 }
    642 
    643 static int snd_pcm_rate_prepare(snd_pcm_t *pcm)
    644 {
    645 	snd_pcm_rate_t *rate = pcm->private_data;
    646 	int err;
    647 
    648 	snd_atomic_write_begin(&rate->watom);
    649 	err = snd_pcm_prepare(rate->gen.slave);
    650 	if (err < 0) {
    651 		snd_atomic_write_end(&rate->watom);
    652 		return err;
    653 	}
    654 	*pcm->hw.ptr = 0;
    655 	*pcm->appl.ptr = 0;
    656 	snd_atomic_write_end(&rate->watom);
    657 	err = snd_pcm_rate_init(pcm);
    658 	if (err < 0)
    659 		return err;
    660 	return 0;
    661 }
    662 
    663 static int snd_pcm_rate_reset(snd_pcm_t *pcm)
    664 {
    665 	snd_pcm_rate_t *rate = pcm->private_data;
    666 	int err;
    667 	snd_atomic_write_begin(&rate->watom);
    668 	err = snd_pcm_reset(rate->gen.slave);
    669 	if (err < 0) {
    670 		snd_atomic_write_end(&rate->watom);
    671 		return err;
    672 	}
    673 	*pcm->hw.ptr = 0;
    674 	*pcm->appl.ptr = 0;
    675 	snd_atomic_write_end(&rate->watom);
    676 	err = snd_pcm_rate_init(pcm);
    677 	if (err < 0)
    678 		return err;
    679 	return 0;
    680 }
    681 
    682 static snd_pcm_sframes_t snd_pcm_rate_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
    683 {
    684 	snd_pcm_rate_t *rate = pcm->private_data;
    685 	snd_pcm_sframes_t n = snd_pcm_mmap_hw_avail(pcm);
    686 
    687 	if ((snd_pcm_uframes_t)n > frames)
    688 		frames = n;
    689 	if (frames == 0)
    690 		return 0;
    691 
    692 	snd_atomic_write_begin(&rate->watom);
    693 	n = snd_pcm_rate_move_applptr(pcm, -frames);
    694 	snd_atomic_write_end(&rate->watom);
    695 	return n;
    696 }
    697 
    698 static snd_pcm_sframes_t snd_pcm_rate_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
    699 {
    700 	snd_pcm_rate_t *rate = pcm->private_data;
    701 	snd_pcm_sframes_t n = snd_pcm_mmap_avail(pcm);
    702 
    703 	if ((snd_pcm_uframes_t)n > frames)
    704 		frames = n;
    705 	if (frames == 0)
    706 		return 0;
    707 
    708 	snd_atomic_write_begin(&rate->watom);
    709 	n = snd_pcm_rate_move_applptr(pcm, frames);
    710 	snd_atomic_write_end(&rate->watom);
    711 	return n;
    712 }
    713 
    714 static int snd_pcm_rate_commit_area(snd_pcm_t *pcm, snd_pcm_rate_t *rate,
    715 				    snd_pcm_uframes_t appl_offset,
    716 				    snd_pcm_uframes_t size,
    717 				    snd_pcm_uframes_t slave_size)
    718 {
    719 	snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset;
    720 	const snd_pcm_channel_area_t *areas;
    721 	const snd_pcm_channel_area_t *slave_areas;
    722 	snd_pcm_uframes_t slave_offset, xfer;
    723 	snd_pcm_uframes_t slave_frames = ULONG_MAX;
    724 	snd_pcm_sframes_t result;
    725 
    726 	areas = snd_pcm_mmap_areas(pcm);
    727 	if (cont >= size) {
    728 		result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
    729 		if (result < 0)
    730 			return result;
    731 		if (slave_frames < slave_size) {
    732 			snd_pcm_rate_write_areas1(pcm, areas, appl_offset, rate->sareas, 0);
    733 			goto __partial;
    734 		}
    735 		snd_pcm_rate_write_areas1(pcm, areas, appl_offset,
    736 					  slave_areas, slave_offset);
    737 		result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, slave_size);
    738 		if (result < (snd_pcm_sframes_t)slave_size) {
    739 			if (result < 0)
    740 				return result;
    741 			result = snd_pcm_rewind(rate->gen.slave, result);
    742 			if (result < 0)
    743 				return result;
    744 			return 0;
    745 		}
    746 	} else {
    747 		snd_pcm_areas_copy(rate->pareas, 0,
    748 				   areas, appl_offset,
    749 				   pcm->channels, cont,
    750 				   pcm->format);
    751 		snd_pcm_areas_copy(rate->pareas, cont,
    752 				   areas, 0,
    753 				   pcm->channels, size - cont,
    754 				   pcm->format);
    755 
    756 		snd_pcm_rate_write_areas1(pcm, rate->pareas, 0, rate->sareas, 0);
    757 
    758 		/* ok, commit first fragment */
    759 		result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
    760 		if (result < 0)
    761 			return result;
    762 	      __partial:
    763 		xfer = 0;
    764 		cont = slave_frames;
    765 		if (cont > slave_size)
    766 			cont = slave_size;
    767 		snd_pcm_areas_copy(slave_areas, slave_offset,
    768 				   rate->sareas, 0,
    769 				   pcm->channels, cont,
    770 				   rate->gen.slave->format);
    771 		result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont);
    772 		if (result < (snd_pcm_sframes_t)cont) {
    773 			if (result < 0)
    774 				return result;
    775 			result = snd_pcm_rewind(rate->gen.slave, result);
    776 			if (result < 0)
    777 				return result;
    778 			return 0;
    779 		}
    780 		xfer = cont;
    781 
    782 		if (xfer == slave_size)
    783 			goto commit_done;
    784 
    785 		/* commit second fragment */
    786 		cont = slave_size - cont;
    787 		slave_frames = cont;
    788 		result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
    789 		if (result < 0)
    790 			return result;
    791 #if 0
    792 		if (slave_offset) {
    793 			SNDERR("non-zero slave_offset %ld", slave_offset);
    794 			return -EIO;
    795 		}
    796 #endif
    797 		snd_pcm_areas_copy(slave_areas, slave_offset,
    798 				   rate->sareas, xfer,
    799 				   pcm->channels, cont,
    800 				   rate->gen.slave->format);
    801 		result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont);
    802 		if (result < (snd_pcm_sframes_t)cont) {
    803 			if (result < 0)
    804 				return result;
    805 			result = snd_pcm_rewind(rate->gen.slave, result + xfer);
    806 			if (result < 0)
    807 				return result;
    808 			return 0;
    809 		}
    810 	}
    811 
    812  commit_done:
    813 	if (rate->start_pending) {
    814 		/* we have pending start-trigger.  let's issue it now */
    815 		snd_pcm_start(rate->gen.slave);
    816 		rate->start_pending = 0;
    817 	}
    818 	return 1;
    819 }
    820 
    821 static int snd_pcm_rate_commit_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t appl_offset)
    822 {
    823 	snd_pcm_rate_t *rate = pcm->private_data;
    824 
    825 	return snd_pcm_rate_commit_area(pcm, rate, appl_offset, pcm->period_size,
    826 					rate->gen.slave->period_size);
    827 }
    828 
    829 static int snd_pcm_rate_grab_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t hw_offset)
    830 {
    831 	snd_pcm_rate_t *rate = pcm->private_data;
    832 	snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset;
    833 	const snd_pcm_channel_area_t *areas;
    834 	const snd_pcm_channel_area_t *slave_areas;
    835 	snd_pcm_uframes_t slave_offset, xfer;
    836 	snd_pcm_uframes_t slave_frames = ULONG_MAX;
    837 	snd_pcm_sframes_t result;
    838 
    839 	areas = snd_pcm_mmap_areas(pcm);
    840 	if (cont >= pcm->period_size) {
    841 		result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
    842 		if (result < 0)
    843 			return result;
    844 		if (slave_frames < rate->gen.slave->period_size)
    845 			goto __partial;
    846 		snd_pcm_rate_read_areas1(pcm, areas, hw_offset,
    847 					 slave_areas, slave_offset);
    848 		result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, rate->gen.slave->period_size);
    849 		if (result < (snd_pcm_sframes_t)rate->gen.slave->period_size) {
    850 			if (result < 0)
    851 				return result;
    852 			result = snd_pcm_rewind(rate->gen.slave, result);
    853 			if (result < 0)
    854 				return result;
    855 			return 0;
    856 		}
    857 	} else {
    858 		/* ok, grab first fragment */
    859 		result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
    860 		if (result < 0)
    861 			return result;
    862 	      __partial:
    863 		xfer = 0;
    864 		cont = slave_frames;
    865 		if (cont > rate->gen.slave->period_size)
    866 			cont = rate->gen.slave->period_size;
    867 		snd_pcm_areas_copy(rate->sareas, 0,
    868 				   slave_areas, slave_offset,
    869 				   pcm->channels, cont,
    870 				   rate->gen.slave->format);
    871 		result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont);
    872 		if (result < (snd_pcm_sframes_t)cont) {
    873 			if (result < 0)
    874 				return result;
    875 			result = snd_pcm_rewind(rate->gen.slave, result);
    876 			if (result < 0)
    877 				return result;
    878 			return 0;
    879 		}
    880 		xfer = cont;
    881 
    882 		if (xfer == rate->gen.slave->period_size)
    883 			goto __transfer;
    884 
    885 		/* grab second fragment */
    886 		cont = rate->gen.slave->period_size - cont;
    887 		slave_frames = cont;
    888 		result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames);
    889 		if (result < 0)
    890 			return result;
    891 #if 0
    892 		if (slave_offset) {
    893 			SNDERR("non-zero slave_offset %ld", slave_offset);
    894 			return -EIO;
    895 		}
    896 #endif
    897 		snd_pcm_areas_copy(rate->sareas, xfer,
    898 		                   slave_areas, slave_offset,
    899 				   pcm->channels, cont,
    900 				   rate->gen.slave->format);
    901 		result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont);
    902 		if (result < (snd_pcm_sframes_t)cont) {
    903 			if (result < 0)
    904 				return result;
    905 			result = snd_pcm_rewind(rate->gen.slave, result + xfer);
    906 			if (result < 0)
    907 				return result;
    908 			return 0;
    909 		}
    910 
    911 	      __transfer:
    912 		cont = pcm->buffer_size - hw_offset;
    913 		if (cont >= pcm->period_size) {
    914 			snd_pcm_rate_read_areas1(pcm, areas, hw_offset,
    915 						 rate->sareas, 0);
    916 		} else {
    917 			snd_pcm_rate_read_areas1(pcm,
    918 						 rate->pareas, 0,
    919 						 rate->sareas, 0);
    920 			snd_pcm_areas_copy(areas, hw_offset,
    921 					   rate->pareas, 0,
    922 					   pcm->channels, cont,
    923 					   pcm->format);
    924 			snd_pcm_areas_copy(areas, 0,
    925 					   rate->pareas, cont,
    926 					   pcm->channels, pcm->period_size - cont,
    927 					   pcm->format);
    928 		}
    929 	}
    930 	return 1;
    931 }
    932 
    933 static int snd_pcm_rate_sync_playback_area(snd_pcm_t *pcm, snd_pcm_uframes_t appl_ptr)
    934 {
    935 	snd_pcm_rate_t *rate = pcm->private_data;
    936 	snd_pcm_t *slave = rate->gen.slave;
    937 	snd_pcm_uframes_t xfer;
    938 	snd_pcm_sframes_t slave_size;
    939 	int err;
    940 
    941 	slave_size = snd_pcm_avail_update(slave);
    942 	if (slave_size < 0)
    943 		return slave_size;
    944 
    945 	if (appl_ptr < rate->last_commit_ptr)
    946 		xfer = appl_ptr - rate->last_commit_ptr + pcm->boundary;
    947 	else
    948 		xfer = appl_ptr - rate->last_commit_ptr;
    949 	while (xfer >= pcm->period_size &&
    950 	       (snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) {
    951 		err = snd_pcm_rate_commit_next_period(pcm, rate->last_commit_ptr % pcm->buffer_size);
    952 		if (err == 0)
    953 			break;
    954 		if (err < 0)
    955 			return err;
    956 		xfer -= pcm->period_size;
    957 		slave_size -= rate->gen.slave->period_size;
    958 		rate->last_commit_ptr += pcm->period_size;
    959 		if (rate->last_commit_ptr >= pcm->boundary)
    960 			rate->last_commit_ptr = 0;
    961 	}
    962 	return 0;
    963 }
    964 
    965 static snd_pcm_sframes_t snd_pcm_rate_mmap_commit(snd_pcm_t *pcm,
    966 						  snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
    967 						  snd_pcm_uframes_t size)
    968 {
    969 	snd_pcm_rate_t *rate = pcm->private_data;
    970 	int err;
    971 
    972 	if (size == 0)
    973 		return 0;
    974 	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
    975 		err = snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr + size);
    976 		if (err < 0)
    977 			return err;
    978 	}
    979 	snd_atomic_write_begin(&rate->watom);
    980 	snd_pcm_mmap_appl_forward(pcm, size);
    981 	snd_atomic_write_end(&rate->watom);
    982 	return size;
    983 }
    984 
    985 static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm)
    986 {
    987 	snd_pcm_rate_t *rate = pcm->private_data;
    988 	snd_pcm_t *slave = rate->gen.slave;
    989 	snd_pcm_uframes_t slave_size;
    990 
    991 	slave_size = snd_pcm_avail_update(slave);
    992 	if (pcm->stream == SND_PCM_STREAM_CAPTURE)
    993 		goto _capture;
    994 	snd_atomic_write_begin(&rate->watom);
    995 	snd_pcm_rate_sync_hwptr(pcm);
    996 	snd_atomic_write_end(&rate->watom);
    997 	snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr);
    998 	return snd_pcm_mmap_avail(pcm);
    999  _capture: {
   1000 	snd_pcm_uframes_t xfer, hw_offset, size;
   1001 
   1002 	xfer = snd_pcm_mmap_capture_avail(pcm);
   1003 	size = pcm->buffer_size - xfer;
   1004 	hw_offset = snd_pcm_mmap_hw_offset(pcm);
   1005 	while (size >= pcm->period_size &&
   1006 	       slave_size >= rate->gen.slave->period_size) {
   1007 		int err = snd_pcm_rate_grab_next_period(pcm, hw_offset);
   1008 		if (err < 0)
   1009 			return err;
   1010 		if (err == 0)
   1011 			return (snd_pcm_sframes_t)xfer;
   1012 		xfer += pcm->period_size;
   1013 		size -= pcm->period_size;
   1014 		slave_size -= rate->gen.slave->period_size;
   1015 		hw_offset += pcm->period_size;
   1016 		hw_offset %= pcm->buffer_size;
   1017 		snd_pcm_mmap_hw_forward(pcm, pcm->period_size);
   1018 	}
   1019 	return (snd_pcm_sframes_t)xfer;
   1020  }
   1021 }
   1022 
   1023 static int snd_pcm_rate_htimestamp(snd_pcm_t *pcm,
   1024 				   snd_pcm_uframes_t *avail,
   1025 				   snd_htimestamp_t *tstamp)
   1026 {
   1027 	snd_pcm_rate_t *rate = pcm->private_data;
   1028 	snd_pcm_sframes_t avail1;
   1029 	snd_pcm_uframes_t tmp;
   1030 	int ok = 0, err;
   1031 
   1032 	while (1) {
   1033 		/* the position is from this plugin itself */
   1034 		avail1 = snd_pcm_avail_update(pcm);
   1035 		if (avail1 < 0)
   1036 			return avail1;
   1037 		if (ok && (snd_pcm_uframes_t)avail1 == *avail)
   1038 			break;
   1039 		*avail = avail1;
   1040 		/* timestamp is taken from the slave PCM */
   1041 		err = snd_pcm_htimestamp(rate->gen.slave, &tmp, tstamp);
   1042 		if (err < 0)
   1043 			return err;
   1044 		ok = 1;
   1045 	}
   1046 	return 0;
   1047 }
   1048 
   1049 static int snd_pcm_rate_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
   1050 {
   1051 	snd_pcm_rate_t *rate = pcm->private_data;
   1052 	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
   1053 		/* Try to sync as much as possible */
   1054 		snd_pcm_rate_hwsync(pcm);
   1055 		snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr);
   1056 	}
   1057 	return snd_pcm_poll_descriptors_revents(rate->gen.slave, pfds, nfds, revents);
   1058 }
   1059 
   1060 static int snd_pcm_rate_drain(snd_pcm_t *pcm)
   1061 {
   1062 	snd_pcm_rate_t *rate = pcm->private_data;
   1063 
   1064 	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
   1065 		/* commit the remaining fraction (if any) */
   1066 		snd_pcm_uframes_t size, ofs, saved_avail_min;
   1067 		snd_pcm_sw_params_t sw_params;
   1068 
   1069 		/* temporarily set avail_min to one */
   1070 		sw_params = rate->sw_params;
   1071 		saved_avail_min = sw_params.avail_min;
   1072 		sw_params.avail_min = 1;
   1073 		snd_pcm_sw_params(rate->gen.slave, &sw_params);
   1074 
   1075 		size = rate->appl_ptr - rate->last_commit_ptr;
   1076 		ofs = rate->last_commit_ptr % pcm->buffer_size;
   1077 		while (size > 0) {
   1078 			snd_pcm_uframes_t psize, spsize;
   1079 
   1080 			if (snd_pcm_wait(rate->gen.slave, -1) < 0)
   1081 				break;
   1082 			if (size > pcm->period_size) {
   1083 				psize = pcm->period_size;
   1084 				spsize = rate->gen.slave->period_size;
   1085 			} else {
   1086 				psize = size;
   1087 				spsize = rate->ops.output_frames(rate->obj, size);
   1088 				if (! spsize)
   1089 					break;
   1090 			}
   1091 			snd_pcm_rate_commit_area(pcm, rate, ofs,
   1092 						 psize, spsize);
   1093 			ofs = (ofs + psize) % pcm->buffer_size;
   1094 			size -= psize;
   1095 		}
   1096 		sw_params.avail_min = saved_avail_min;
   1097 		snd_pcm_sw_params(rate->gen.slave, &sw_params);
   1098 	}
   1099 	return snd_pcm_drain(rate->gen.slave);
   1100 }
   1101 
   1102 static snd_pcm_state_t snd_pcm_rate_state(snd_pcm_t *pcm)
   1103 {
   1104 	snd_pcm_rate_t *rate = pcm->private_data;
   1105 	if (rate->start_pending) /* pseudo-state */
   1106 		return SND_PCM_STATE_RUNNING;
   1107 	return snd_pcm_state(rate->gen.slave);
   1108 }
   1109 
   1110 
   1111 static int snd_pcm_rate_start(snd_pcm_t *pcm)
   1112 {
   1113 	snd_pcm_rate_t *rate = pcm->private_data;
   1114 	snd_pcm_uframes_t avail;
   1115 
   1116 	if (pcm->stream == SND_PCM_STREAM_CAPTURE)
   1117 		return snd_pcm_start(rate->gen.slave);
   1118 
   1119 	if (snd_pcm_state(rate->gen.slave) != SND_PCM_STATE_PREPARED)
   1120 		return -EBADFD;
   1121 
   1122 	gettimestamp(&rate->trigger_tstamp, pcm->monotonic);
   1123 
   1124 	avail = snd_pcm_mmap_playback_hw_avail(rate->gen.slave);
   1125 	if (avail == 0) {
   1126 		/* postpone the trigger since we have no data committed yet */
   1127 		rate->start_pending = 1;
   1128 		return 0;
   1129 	}
   1130 	rate->start_pending = 0;
   1131 	return snd_pcm_start(rate->gen.slave);
   1132 }
   1133 
   1134 static int snd_pcm_rate_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
   1135 {
   1136 	snd_pcm_rate_t *rate = pcm->private_data;
   1137 	snd_pcm_sframes_t err;
   1138 	snd_atomic_read_t ratom;
   1139 	snd_atomic_read_init(&ratom, &rate->watom);
   1140  _again:
   1141 	snd_atomic_read_begin(&ratom);
   1142 	err = snd_pcm_status(rate->gen.slave, status);
   1143 	if (err < 0) {
   1144 		snd_atomic_read_ok(&ratom);
   1145 		return err;
   1146 	}
   1147 	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
   1148 		if (rate->start_pending)
   1149 			status->state = SND_PCM_STATE_RUNNING;
   1150 		status->trigger_tstamp = rate->trigger_tstamp;
   1151 	}
   1152 	snd_pcm_rate_sync_hwptr(pcm);
   1153 	status->appl_ptr = *pcm->appl.ptr;
   1154 	status->hw_ptr = *pcm->hw.ptr;
   1155 	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
   1156 		status->delay = snd_pcm_mmap_playback_hw_avail(pcm);
   1157 		status->avail = snd_pcm_mmap_playback_avail(pcm);
   1158 		status->avail_max = rate->ops.input_frames(rate->obj, status->avail_max);
   1159 	} else {
   1160 		status->delay = snd_pcm_mmap_capture_hw_avail(pcm);
   1161 		status->avail = snd_pcm_mmap_capture_avail(pcm);
   1162 		status->avail_max = rate->ops.output_frames(rate->obj, status->avail_max);
   1163 	}
   1164 	if (!snd_atomic_read_ok(&ratom)) {
   1165 		snd_atomic_read_wait(&ratom);
   1166 		goto _again;
   1167 	}
   1168 	return 0;
   1169 }
   1170 
   1171 static void snd_pcm_rate_dump(snd_pcm_t *pcm, snd_output_t *out)
   1172 {
   1173 	snd_pcm_rate_t *rate = pcm->private_data;
   1174 	if (rate->sformat == SND_PCM_FORMAT_UNKNOWN)
   1175 		snd_output_printf(out, "Rate conversion PCM (%d)\n",
   1176 			rate->srate);
   1177 	else
   1178 		snd_output_printf(out, "Rate conversion PCM (%d, sformat=%s)\n",
   1179 			rate->srate,
   1180 			snd_pcm_format_name(rate->sformat));
   1181 	if (pcm->setup) {
   1182 		snd_output_printf(out, "Its setup is:\n");
   1183 		snd_pcm_dump_setup(pcm, out);
   1184 	}
   1185 	snd_output_printf(out, "Slave: ");
   1186 	snd_pcm_dump(rate->gen.slave, out);
   1187 }
   1188 
   1189 static int snd_pcm_rate_close(snd_pcm_t *pcm)
   1190 {
   1191 	snd_pcm_rate_t *rate = pcm->private_data;
   1192 
   1193 	if (rate->ops.close)
   1194 		rate->ops.close(rate->obj);
   1195 	return snd_pcm_generic_close(pcm);
   1196 }
   1197 
   1198 static const snd_pcm_fast_ops_t snd_pcm_rate_fast_ops = {
   1199 	.status = snd_pcm_rate_status,
   1200 	.state = snd_pcm_rate_state,
   1201 	.hwsync = snd_pcm_rate_hwsync,
   1202 	.delay = snd_pcm_rate_delay,
   1203 	.prepare = snd_pcm_rate_prepare,
   1204 	.reset = snd_pcm_rate_reset,
   1205 	.start = snd_pcm_rate_start,
   1206 	.drop = snd_pcm_generic_drop,
   1207 	.drain = snd_pcm_rate_drain,
   1208 	.pause = snd_pcm_generic_pause,
   1209 	.rewind = snd_pcm_rate_rewind,
   1210 	.forward = snd_pcm_rate_forward,
   1211 	.resume = snd_pcm_generic_resume,
   1212 	.writei = snd_pcm_mmap_writei,
   1213 	.writen = snd_pcm_mmap_writen,
   1214 	.readi = snd_pcm_mmap_readi,
   1215 	.readn = snd_pcm_mmap_readn,
   1216 	.avail_update = snd_pcm_rate_avail_update,
   1217 	.mmap_commit = snd_pcm_rate_mmap_commit,
   1218 	.htimestamp = snd_pcm_rate_htimestamp,
   1219 	.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
   1220 	.poll_descriptors = snd_pcm_generic_poll_descriptors,
   1221 	.poll_revents = snd_pcm_rate_poll_revents,
   1222 };
   1223 
   1224 static const snd_pcm_ops_t snd_pcm_rate_ops = {
   1225 	.close = snd_pcm_rate_close,
   1226 	.info = snd_pcm_generic_info,
   1227 	.hw_refine = snd_pcm_rate_hw_refine,
   1228 	.hw_params = snd_pcm_rate_hw_params,
   1229 	.hw_free = snd_pcm_rate_hw_free,
   1230 	.sw_params = snd_pcm_rate_sw_params,
   1231 	.channel_info = snd_pcm_generic_channel_info,
   1232 	.dump = snd_pcm_rate_dump,
   1233 	.nonblock = snd_pcm_generic_nonblock,
   1234 	.async = snd_pcm_generic_async,
   1235 	.mmap = snd_pcm_generic_mmap,
   1236 	.munmap = snd_pcm_generic_munmap,
   1237 };
   1238 
   1239 /**
   1240  * \brief Get a default converter string
   1241  * \param root Root configuration node
   1242  * \retval A const config item if found, or NULL
   1243  */
   1244 const snd_config_t *snd_pcm_rate_get_default_converter(snd_config_t *root)
   1245 {
   1246 	snd_config_t *n;
   1247 	/* look for default definition */
   1248 	if (snd_config_search(root, "defaults.pcm.rate_converter", &n) >= 0)
   1249 		return n;
   1250 	return NULL;
   1251 }
   1252 
   1253 #ifdef PIC
   1254 static int is_builtin_plugin(const char *type)
   1255 {
   1256 	return strcmp(type, "linear") == 0;
   1257 }
   1258 
   1259 static const char *const default_rate_plugins[] = {
   1260 	"speexrate", "linear", NULL
   1261 };
   1262 
   1263 static int rate_open_func(snd_pcm_rate_t *rate, const char *type)
   1264 {
   1265 	char open_name[64];
   1266 	snd_pcm_rate_open_func_t open_func;
   1267 
   1268 	snprintf(open_name, sizeof(open_name), "_snd_pcm_rate_%s_open", type);
   1269 	open_func = snd_dlobj_cache_lookup(open_name);
   1270 	if (!open_func) {
   1271 		void *h;
   1272 		char lib_name[128], *lib = NULL;
   1273 		if (!is_builtin_plugin(type)) {
   1274 			snprintf(lib_name, sizeof(lib_name),
   1275 				 "%s/libasound_module_rate_%s.so", ALSA_PLUGIN_DIR, type);
   1276 			lib = lib_name;
   1277 		}
   1278 		h = snd_dlopen(lib, RTLD_NOW);
   1279 		if (!h)
   1280 			return -ENOENT;
   1281 		open_func = snd_dlsym(h, open_name, NULL);
   1282 		if (!open_func) {
   1283 			snd_dlclose(h);
   1284 			return -ENOENT;
   1285 		}
   1286 		snd_dlobj_cache_add(open_name, h, open_func);
   1287 	}
   1288 	return open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops);
   1289 }
   1290 #endif
   1291 
   1292 /**
   1293  * \brief Creates a new rate PCM
   1294  * \param pcmp Returns created PCM handle
   1295  * \param name Name of PCM
   1296  * \param sformat Slave format
   1297  * \param srate Slave rate
   1298  * \param type SRC type string
   1299  * \param slave Slave PCM handle
   1300  * \param close_slave When set, the slave PCM handle is closed with copy PCM
   1301  * \retval zero on success otherwise a negative error code
   1302  * \warning Using of this function might be dangerous in the sense
   1303  *          of compatibility reasons. The prototype might be freely
   1304  *          changed in future.
   1305  */
   1306 int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name,
   1307 		      snd_pcm_format_t sformat, unsigned int srate,
   1308 		      const snd_config_t *converter,
   1309 		      snd_pcm_t *slave, int close_slave)
   1310 {
   1311 	snd_pcm_t *pcm;
   1312 	snd_pcm_rate_t *rate;
   1313 	const char *type = NULL;
   1314 	int err;
   1315 #ifndef PIC
   1316 	snd_pcm_rate_open_func_t open_func;
   1317 	extern int SND_PCM_RATE_PLUGIN_ENTRY(linear) (unsigned int version, void **objp, snd_pcm_rate_ops_t *ops);
   1318 #endif
   1319 
   1320 	assert(pcmp && slave);
   1321 	if (sformat != SND_PCM_FORMAT_UNKNOWN &&
   1322 	    snd_pcm_format_linear(sformat) != 1)
   1323 		return -EINVAL;
   1324 	rate = calloc(1, sizeof(snd_pcm_rate_t));
   1325 	if (!rate) {
   1326 		return -ENOMEM;
   1327 	}
   1328 	rate->gen.slave = slave;
   1329 	rate->gen.close_slave = close_slave;
   1330 	rate->srate = srate;
   1331 	rate->sformat = sformat;
   1332 	snd_atomic_write_init(&rate->watom);
   1333 
   1334 	err = snd_pcm_new(&pcm, SND_PCM_TYPE_RATE, name, slave->stream, slave->mode);
   1335 	if (err < 0) {
   1336 		free(rate);
   1337 		return err;
   1338 	}
   1339 
   1340 #ifdef PIC
   1341 	err = -ENOENT;
   1342 	if (!converter) {
   1343 		const char *const *types;
   1344 		for (types = default_rate_plugins; *types; types++) {
   1345 			err = rate_open_func(rate, *types);
   1346 			if (!err) {
   1347 				type = *types;
   1348 				break;
   1349 			}
   1350 		}
   1351 	} else if (!snd_config_get_string(converter, &type))
   1352 		err = rate_open_func(rate, type);
   1353 	else if (snd_config_get_type(converter) == SND_CONFIG_TYPE_COMPOUND) {
   1354 		snd_config_iterator_t i, next;
   1355 		snd_config_for_each(i, next, converter) {
   1356 			snd_config_t *n = snd_config_iterator_entry(i);
   1357 			if (snd_config_get_string(n, &type) < 0)
   1358 				break;
   1359 			err = rate_open_func(rate, type);
   1360 			if (!err)
   1361 				break;
   1362 		}
   1363 	} else {
   1364 		SNDERR("Invalid type for rate converter");
   1365 		snd_pcm_close(pcm);
   1366 		return -EINVAL;
   1367 	}
   1368 	if (err < 0) {
   1369 		SNDERR("Cannot find rate converter");
   1370 		snd_pcm_close(pcm);
   1371 		return -ENOENT;
   1372 	}
   1373 #else
   1374 	type = "linear";
   1375 	open_func = SND_PCM_RATE_PLUGIN_ENTRY(linear);
   1376 	err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops);
   1377 	if (err < 0) {
   1378 		snd_pcm_close(pcm);
   1379 		return err;
   1380 	}
   1381 #endif
   1382 
   1383 	if (! rate->ops.init || ! (rate->ops.convert || rate->ops.convert_s16) ||
   1384 	    ! rate->ops.input_frames || ! rate->ops.output_frames) {
   1385 		SNDERR("Inproper rate plugin %s initialization", type);
   1386 		snd_pcm_close(pcm);
   1387 		return err;
   1388 	}
   1389 
   1390 	pcm->ops = &snd_pcm_rate_ops;
   1391 	pcm->fast_ops = &snd_pcm_rate_fast_ops;
   1392 	pcm->private_data = rate;
   1393 	pcm->poll_fd = slave->poll_fd;
   1394 	pcm->poll_events = slave->poll_events;
   1395 	pcm->mmap_rw = 1;
   1396 	pcm->monotonic = slave->monotonic;
   1397 	snd_pcm_set_hw_ptr(pcm, &rate->hw_ptr, -1, 0);
   1398 	snd_pcm_set_appl_ptr(pcm, &rate->appl_ptr, -1, 0);
   1399 	*pcmp = pcm;
   1400 
   1401 	return 0;
   1402 }
   1403 
   1404 /*! \page pcm_plugins
   1405 
   1406 \section pcm_plugins_rate Plugin: Rate
   1407 
   1408 This plugin converts a stream rate. The input and output formats must be linear.
   1409 
   1410 \code
   1411 pcm.name {
   1412 	type rate               # Rate PCM
   1413         slave STR               # Slave name
   1414         # or
   1415         slave {                 # Slave definition
   1416                 pcm STR         # Slave PCM name
   1417                 # or
   1418                 pcm { }         # Slave PCM definition
   1419                 rate INT        # Slave rate
   1420                 [format STR]    # Slave format
   1421         }
   1422 	converter STR			# optional
   1423 	# or
   1424 	converter [ STR1 STR2 ... ]	# optional
   1425 				# Converter type, default is taken from
   1426 				# defaults.pcm.rate_converter
   1427 }
   1428 \endcode
   1429 
   1430 \subsection pcm_plugins_rate_funcref Function reference
   1431 
   1432 <UL>
   1433   <LI>snd_pcm_rate_open()
   1434   <LI>_snd_pcm_rate_open()
   1435 </UL>
   1436 
   1437 */
   1438 
   1439 /**
   1440  * \brief Creates a new rate PCM
   1441  * \param pcmp Returns created PCM handle
   1442  * \param name Name of PCM
   1443  * \param root Root configuration node
   1444  * \param conf Configuration node with rate PCM description
   1445  * \param stream Stream type
   1446  * \param mode Stream mode
   1447  * \retval zero on success otherwise a negative error code
   1448  * \warning Using of this function might be dangerous in the sense
   1449  *          of compatibility reasons. The prototype might be freely
   1450  *          changed in future.
   1451  */
   1452 int _snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name,
   1453 		       snd_config_t *root, snd_config_t *conf,
   1454 		       snd_pcm_stream_t stream, int mode)
   1455 {
   1456 	snd_config_iterator_t i, next;
   1457 	int err;
   1458 	snd_pcm_t *spcm;
   1459 	snd_config_t *slave = NULL, *sconf;
   1460 	snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN;
   1461 	int srate = -1;
   1462 	const snd_config_t *converter = NULL;
   1463 
   1464 	snd_config_for_each(i, next, conf) {
   1465 		snd_config_t *n = snd_config_iterator_entry(i);
   1466 		const char *id;
   1467 		if (snd_config_get_id(n, &id) < 0)
   1468 			continue;
   1469 		if (snd_pcm_conf_generic_id(id))
   1470 			continue;
   1471 		if (strcmp(id, "slave") == 0) {
   1472 			slave = n;
   1473 			continue;
   1474 		}
   1475 		if (strcmp(id, "converter") == 0) {
   1476 			converter = n;
   1477 			continue;
   1478 		}
   1479 		SNDERR("Unknown field %s", id);
   1480 		return -EINVAL;
   1481 	}
   1482 	if (!slave) {
   1483 		SNDERR("slave is not defined");
   1484 		return -EINVAL;
   1485 	}
   1486 
   1487 	err = snd_pcm_slave_conf(root, slave, &sconf, 2,
   1488 				 SND_PCM_HW_PARAM_FORMAT, 0, &sformat,
   1489 				 SND_PCM_HW_PARAM_RATE, SCONF_MANDATORY, &srate);
   1490 	if (err < 0)
   1491 		return err;
   1492 	if (sformat != SND_PCM_FORMAT_UNKNOWN &&
   1493 	    snd_pcm_format_linear(sformat) != 1) {
   1494 	    	snd_config_delete(sconf);
   1495 		SNDERR("slave format is not linear");
   1496 		return -EINVAL;
   1497 	}
   1498 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
   1499 	snd_config_delete(sconf);
   1500 	if (err < 0)
   1501 		return err;
   1502 	err = snd_pcm_rate_open(pcmp, name, sformat, (unsigned int) srate,
   1503 				converter, spcm, 1);
   1504 	if (err < 0)
   1505 		snd_pcm_close(spcm);
   1506 	return err;
   1507 }
   1508 #ifndef DOC_HIDDEN
   1509 SND_DLSYM_BUILD_VERSION(_snd_pcm_rate_open, SND_PCM_DLSYM_VERSION);
   1510 #endif
   1511