1/** 2 * \file pcm/pcm_rate.c 3 * \ingroup PCM_Plugins 4 * \brief PCM Rate Plugin Interface 5 * \author Abramo Bagnara <abramo@alsa-project.org> 6 * \author Jaroslav Kysela <perex@perex.cz> 7 * \date 2000-2004 8 */ 9/* 10 * PCM - Rate conversion 11 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> 12 * 2004 by Jaroslav Kysela <perex@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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 28 * 29 */ 30#include "pcm_local.h" 31#include "pcm_plugin.h" 32#include "pcm_rate.h" 33#include "plugin_ops.h" 34#include "bswap.h" 35#include <inttypes.h> 36 37#if 0 38#define DEBUG_REFINE 39#endif 40 41#ifndef PIC 42/* entry for static linking */ 43const char *_snd_module_pcm_rate = ""; 44#endif 45 46#ifndef DOC_HIDDEN 47 48typedef struct _snd_pcm_rate snd_pcm_rate_t; 49 50struct _snd_pcm_rate { 51 snd_pcm_generic_t gen; 52 snd_pcm_uframes_t appl_ptr, hw_ptr, last_slave_hw_ptr; 53 snd_pcm_uframes_t last_commit_ptr; 54 snd_pcm_uframes_t orig_avail_min; 55 snd_pcm_sw_params_t sw_params; 56 snd_pcm_format_t sformat; 57 unsigned int srate; 58 snd_pcm_channel_area_t *pareas; /* areas for splitted period (rate pcm) */ 59 snd_pcm_channel_area_t *sareas; /* areas for splitted period (slave pcm) */ 60 snd_pcm_rate_info_t info; 61 void *open_func; 62 void *obj; 63 snd_pcm_rate_ops_t ops; 64 unsigned int src_conv_idx; 65 unsigned int dst_conv_idx; 66 snd_pcm_channel_area_t *src_buf; 67 snd_pcm_channel_area_t *dst_buf; 68 int start_pending; /* start is triggered but not commited to slave */ 69 snd_htimestamp_t trigger_tstamp; 70 unsigned int plugin_version; 71 unsigned int rate_min, rate_max; 72 snd_pcm_format_t orig_in_format; 73 snd_pcm_format_t orig_out_format; 74 uint64_t in_formats; 75 uint64_t out_formats; 76 unsigned int format_flags; 77}; 78 79#define SND_PCM_RATE_PLUGIN_VERSION_OLD 0x010001 /* old rate plugin */ 80#endif /* DOC_HIDDEN */ 81 82/* allocate a channel area and a temporary buffer for the given size */ 83static snd_pcm_channel_area_t * 84rate_alloc_tmp_buf(snd_pcm_format_t format, 85 unsigned int channels, unsigned int frames) 86{ 87 snd_pcm_channel_area_t *ap; 88 int width = snd_pcm_format_physical_width(format); 89 unsigned int i; 90 91 ap = malloc(sizeof(*ap) * channels); 92 if (!ap) 93 return NULL; 94 ap->addr = malloc(frames * channels * width / 8); 95 if (!ap->addr) { 96 free(ap); 97 return NULL; 98 } 99 100 /* set up in interleaved format */ 101 for (i = 0; i < channels; i++) { 102 ap[i].addr = ap[0].addr + (i * width) / 8; 103 ap[i].first = 0; 104 ap[i].step = width * channels; 105 } 106 107 return ap; 108} 109 110static void rate_free_tmp_buf(snd_pcm_channel_area_t **ptr) 111{ 112 snd_pcm_channel_area_t *c = *ptr; 113 114 if (c) { 115 free(c->addr); 116 free(c); 117 *ptr = NULL; 118 } 119} 120 121static int snd_pcm_rate_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) 122{ 123 snd_pcm_rate_t *rate = pcm->private_data; 124 int err; 125 snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; 126 snd_pcm_format_mask_t format_mask = { SND_PCM_FMTBIT_LINEAR }; 127 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, 128 &access_mask); 129 if (err < 0) 130 return err; 131 err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT, 132 &format_mask); 133 if (err < 0) 134 return err; 135 err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD); 136 if (err < 0) 137 return err; 138 if (rate->rate_min) { 139 err = _snd_pcm_hw_param_set_min(params, SND_PCM_HW_PARAM_RATE, 140 rate->rate_min, 0); 141 if (err < 0) 142 return err; 143 } 144 if (rate->rate_max) { 145 err = _snd_pcm_hw_param_set_max(params, SND_PCM_HW_PARAM_RATE, 146 rate->rate_max, 0); 147 if (err < 0) 148 return err; 149 } 150 params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); 151 return 0; 152} 153 154static int snd_pcm_rate_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) 155{ 156 snd_pcm_rate_t *rate = pcm->private_data; 157 snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; 158 _snd_pcm_hw_params_any(sparams); 159 _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, 160 &saccess_mask); 161 if (rate->sformat != SND_PCM_FORMAT_UNKNOWN) { 162 _snd_pcm_hw_params_set_format(sparams, rate->sformat); 163 _snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD); 164 } 165 _snd_pcm_hw_param_set_minmax(sparams, SND_PCM_HW_PARAM_RATE, 166 rate->srate, 0, rate->srate + 1, -1); 167 return 0; 168} 169 170static int snd_pcm_rate_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 171 snd_pcm_hw_params_t *sparams) 172{ 173 snd_pcm_rate_t *rate = pcm->private_data; 174 snd_interval_t t, buffer_size; 175 const snd_interval_t *srate, *crate; 176 int err; 177 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | 178 SND_PCM_HW_PARBIT_PERIOD_TIME | 179 SND_PCM_HW_PARBIT_TICK_TIME); 180 if (rate->sformat == SND_PCM_FORMAT_UNKNOWN) 181 links |= (SND_PCM_HW_PARBIT_FORMAT | 182 SND_PCM_HW_PARBIT_SUBFORMAT | 183 SND_PCM_HW_PARBIT_SAMPLE_BITS | 184 SND_PCM_HW_PARBIT_FRAME_BITS); 185 snd_interval_copy(&buffer_size, snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE)); 186 snd_interval_unfloor(&buffer_size); 187 crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE); 188 srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE); 189 snd_interval_muldiv(&buffer_size, srate, crate, &t); 190 err = _snd_pcm_hw_param_set_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); 191 if (err < 0) 192 return err; 193 err = _snd_pcm_hw_params_refine(sparams, links, params); 194 if (err < 0) 195 return err; 196 return 0; 197} 198 199static int snd_pcm_rate_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, 200 snd_pcm_hw_params_t *sparams) 201{ 202 snd_pcm_rate_t *rate = pcm->private_data; 203 snd_interval_t t; 204#ifdef DEBUG_REFINE 205 snd_output_t *out; 206#endif 207 const snd_interval_t *sbuffer_size, *buffer_size; 208 const snd_interval_t *srate, *crate; 209 int err; 210 unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS | 211 SND_PCM_HW_PARBIT_PERIOD_TIME | 212 SND_PCM_HW_PARBIT_TICK_TIME); 213 if (rate->sformat == SND_PCM_FORMAT_UNKNOWN) 214 links |= (SND_PCM_HW_PARBIT_FORMAT | 215 SND_PCM_HW_PARBIT_SUBFORMAT | 216 SND_PCM_HW_PARBIT_SAMPLE_BITS | 217 SND_PCM_HW_PARBIT_FRAME_BITS); 218 sbuffer_size = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE); 219 crate = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_RATE); 220 srate = snd_pcm_hw_param_get_interval(sparams, SND_PCM_HW_PARAM_RATE); 221 snd_interval_muldiv(sbuffer_size, crate, srate, &t); 222 snd_interval_floor(&t); 223 err = _snd_pcm_hw_param_set_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t); 224 if (err < 0) 225 return err; 226 buffer_size = snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE); 227 /* 228 * this condition probably needs more work: 229 * in case when the buffer_size is known and we are looking 230 * for best period_size, we should prefer situation when 231 * (buffer_size / period_size) * period_size == buffer_size 232 */ 233 if (snd_interval_single(buffer_size) && buffer_size->integer) { 234 snd_interval_t *period_size; 235 period_size = (snd_interval_t *)snd_pcm_hw_param_get_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE); 236 if (!snd_interval_checkempty(period_size) && 237 period_size->openmin && period_size->openmax && 238 period_size->min + 1 == period_size->max) { 239 if (period_size->min > 0 && (buffer_size->min / period_size->min) * period_size->min == buffer_size->min) { 240 snd_interval_set_value(period_size, period_size->min); 241 } else if ((buffer_size->max / period_size->max) * period_size->max == buffer_size->max) { 242 snd_interval_set_value(period_size, period_size->max); 243 } 244 } 245 } 246#ifdef DEBUG_REFINE 247 snd_output_stdio_attach(&out, stderr, 0); 248 snd_output_printf(out, "REFINE (params):\n"); 249 snd_pcm_hw_params_dump(params, out); 250 snd_output_printf(out, "REFINE (slave params):\n"); 251 snd_pcm_hw_params_dump(sparams, out); 252 snd_output_close(out); 253#endif 254 err = _snd_pcm_hw_params_refine(params, links, sparams); 255#ifdef DEBUG_REFINE 256 snd_output_stdio_attach(&out, stderr, 0); 257 snd_output_printf(out, "********************\n"); 258 snd_output_printf(out, "REFINE (params) (%i):\n", err); 259 snd_pcm_hw_params_dump(params, out); 260 snd_output_printf(out, "REFINE (slave params):\n"); 261 snd_pcm_hw_params_dump(sparams, out); 262 snd_output_close(out); 263#endif 264 if (err < 0) 265 return err; 266 return 0; 267} 268 269static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm, 270 snd_pcm_hw_params_t *params) 271{ 272 return snd_pcm_hw_refine_slave(pcm, params, 273 snd_pcm_rate_hw_refine_cprepare, 274 snd_pcm_rate_hw_refine_cchange, 275 snd_pcm_rate_hw_refine_sprepare, 276 snd_pcm_rate_hw_refine_schange, 277 snd_pcm_generic_hw_refine); 278} 279 280/* evaluate the best matching available format to the given format */ 281static int get_best_format(uint64_t mask, snd_pcm_format_t orig) 282{ 283 int pwidth = snd_pcm_format_physical_width(orig); 284 int width = snd_pcm_format_width(orig); 285 int signd = snd_pcm_format_signed(orig); 286 int best_score = -1; 287 int match = -1; 288 int f, score; 289 290 for (f = 0; f <= SND_PCM_FORMAT_LAST; f++) { 291 if (!(mask & (1ULL << f))) 292 continue; 293 score = 0; 294 if (snd_pcm_format_linear(f)) { 295 if (snd_pcm_format_physical_width(f) == pwidth) 296 score++; 297 if (snd_pcm_format_physical_width(f) >= pwidth) 298 score++; 299 if (snd_pcm_format_width(f) == width) 300 score++; 301 if (snd_pcm_format_signed(f) == signd) 302 score++; 303 } 304 if (score > best_score) { 305 match = f; 306 best_score = score; 307 } 308 } 309 310 return match; 311} 312 313/* set up the input and output formats from the available lists */ 314static int choose_preferred_format(snd_pcm_rate_t *rate) 315{ 316 uint64_t in_mask = rate->in_formats; 317 uint64_t out_mask = rate->out_formats; 318 int in, out; 319 320 if (!in_mask || !out_mask) 321 return 0; 322 323 if (rate->orig_in_format == rate->orig_out_format) 324 if (in_mask & out_mask & (1ULL << rate->orig_in_format)) 325 return 0; /* nothing changed */ 326 327 repeat: 328 in = get_best_format(in_mask, rate->orig_in_format); 329 out = get_best_format(out_mask, rate->orig_out_format); 330 if (in < 0 || out < 0) 331 return -ENOENT; 332 333 if ((rate->format_flags & SND_PCM_RATE_FLAG_SYNC_FORMATS) && 334 in != out) { 335 if (out_mask & (1ULL << in)) 336 out = in; 337 else if (in_mask & (1ULL << out)) 338 in = out; 339 else { 340 in_mask &= ~(1ULL << in); 341 out_mask &= ~(1ULL << out); 342 goto repeat; 343 } 344 } 345 346 rate->info.in.format = in; 347 rate->info.out.format = out; 348 return 0; 349} 350 351static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) 352{ 353 snd_pcm_rate_t *rate = pcm->private_data; 354 snd_pcm_t *slave = rate->gen.slave; 355 snd_pcm_rate_side_info_t *sinfo, *cinfo; 356 unsigned int channels, acc; 357 int need_src_buf, need_dst_buf; 358 int err = snd_pcm_hw_params_slave(pcm, params, 359 snd_pcm_rate_hw_refine_cchange, 360 snd_pcm_rate_hw_refine_sprepare, 361 snd_pcm_rate_hw_refine_schange, 362 snd_pcm_generic_hw_params); 363 if (err < 0) 364 return err; 365 366 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 367 cinfo = &rate->info.in; 368 sinfo = &rate->info.out; 369 } else { 370 sinfo = &rate->info.in; 371 cinfo = &rate->info.out; 372 } 373 err = INTERNAL(snd_pcm_hw_params_get_format)(params, &cinfo->format); 374 if (err < 0) 375 return err; 376 err = INTERNAL(snd_pcm_hw_params_get_rate)(params, &cinfo->rate, 0); 377 if (err < 0) 378 return err; 379 err = INTERNAL(snd_pcm_hw_params_get_period_size)(params, &cinfo->period_size, 0); 380 if (err < 0) 381 return err; 382 err = INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &cinfo->buffer_size); 383 if (err < 0) 384 return err; 385 err = INTERNAL(snd_pcm_hw_params_get_channels)(params, &channels); 386 if (err < 0) 387 return err; 388 err = INTERNAL(snd_pcm_hw_params_get_access)(params, &acc); 389 if (err < 0) 390 return err; 391 392 rate->info.channels = channels; 393 sinfo->format = slave->format; 394 sinfo->rate = slave->rate; 395 sinfo->buffer_size = slave->buffer_size; 396 sinfo->period_size = slave->period_size; 397 398 if (CHECK_SANITY(rate->pareas)) { 399 SNDMSG("rate plugin already in use"); 400 return -EBUSY; 401 } 402 403 rate->pareas = rate_alloc_tmp_buf(cinfo->format, channels, 404 cinfo->period_size); 405 rate->sareas = rate_alloc_tmp_buf(sinfo->format, channels, 406 sinfo->period_size); 407 if (!rate->pareas || !rate->sareas) { 408 err = -ENOMEM; 409 goto error_pareas; 410 } 411 412 rate->orig_in_format = rate->info.in.format; 413 rate->orig_out_format = rate->info.out.format; 414 if (choose_preferred_format(rate) < 0) { 415 SNDERR("No matching format in rate plugin"); 416 err = -EINVAL; 417 goto error_pareas; 418 } 419 420 err = rate->ops.init(rate->obj, &rate->info); 421 if (err < 0) 422 goto error_init; 423 424 rate_free_tmp_buf(&rate->src_buf); 425 rate_free_tmp_buf(&rate->dst_buf); 426 427 need_src_buf = need_dst_buf = 0; 428 429 if ((rate->format_flags & SND_PCM_RATE_FLAG_INTERLEAVED) && 430 !(acc == SND_PCM_ACCESS_MMAP_INTERLEAVED || 431 acc == SND_PCM_ACCESS_RW_INTERLEAVED)) { 432 need_src_buf = need_dst_buf = 1; 433 } else { 434 if (rate->orig_in_format != rate->info.in.format) 435 need_src_buf = 1; 436 if (rate->orig_out_format != rate->info.out.format) 437 need_dst_buf = 1; 438 } 439 440 if (need_src_buf) { 441 rate->src_conv_idx = 442 snd_pcm_linear_convert_index(rate->orig_in_format, 443 rate->info.in.format); 444 rate->src_buf = rate_alloc_tmp_buf(rate->info.in.format, 445 channels, rate->info.in.period_size); 446 if (!rate->src_buf) { 447 err = -ENOMEM; 448 goto error; 449 } 450 } 451 452 if (need_dst_buf) { 453 rate->dst_conv_idx = 454 snd_pcm_linear_convert_index(rate->info.out.format, 455 rate->orig_out_format); 456 rate->dst_buf = rate_alloc_tmp_buf(rate->info.out.format, 457 channels, rate->info.out.period_size); 458 if (!rate->dst_buf) { 459 err = -ENOMEM; 460 goto error; 461 } 462 } 463 464 return 0; 465 466 error: 467 rate_free_tmp_buf(&rate->src_buf); 468 rate_free_tmp_buf(&rate->dst_buf); 469 error_init: 470 if (rate->ops.free) 471 rate->ops.free(rate->obj); 472 error_pareas: 473 rate_free_tmp_buf(&rate->pareas); 474 rate_free_tmp_buf(&rate->sareas); 475 return err; 476} 477 478static int snd_pcm_rate_hw_free(snd_pcm_t *pcm) 479{ 480 snd_pcm_rate_t *rate = pcm->private_data; 481 482 rate_free_tmp_buf(&rate->pareas); 483 rate_free_tmp_buf(&rate->sareas); 484 if (rate->ops.free) 485 rate->ops.free(rate->obj); 486 rate_free_tmp_buf(&rate->src_buf); 487 rate_free_tmp_buf(&rate->dst_buf); 488 return snd_pcm_hw_free(rate->gen.slave); 489} 490 491static void recalc(snd_pcm_t *pcm, snd_pcm_uframes_t *val) 492{ 493 snd_pcm_rate_t *rate = pcm->private_data; 494 snd_pcm_t *slave = rate->gen.slave; 495 unsigned long div; 496 497 if (*val == pcm->buffer_size) { 498 *val = slave->buffer_size; 499 } else { 500 div = *val / pcm->period_size; 501 if (div * pcm->period_size == *val) 502 *val = div * slave->period_size; 503 else 504 *val = muldiv_near(*val, slave->period_size, pcm->period_size); 505 } 506} 507 508static int snd_pcm_rate_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) 509{ 510 snd_pcm_rate_t *rate = pcm->private_data; 511 snd_pcm_t *slave = rate->gen.slave; 512 snd_pcm_sw_params_t *sparams; 513 snd_pcm_uframes_t boundary1, boundary2, sboundary; 514 int err; 515 516 sparams = &rate->sw_params; 517 err = snd_pcm_sw_params_current(slave, sparams); 518 if (err < 0) 519 return err; 520 sboundary = sparams->boundary; 521 *sparams = *params; 522 boundary1 = pcm->buffer_size; 523 boundary2 = slave->buffer_size; 524 while (boundary1 * 2 <= LONG_MAX - pcm->buffer_size && 525 boundary2 * 2 <= LONG_MAX - slave->buffer_size) { 526 boundary1 *= 2; 527 boundary2 *= 2; 528 } 529 params->boundary = boundary1; 530 sparams->boundary = sboundary; 531 532 if (rate->ops.adjust_pitch) 533 rate->ops.adjust_pitch(rate->obj, &rate->info); 534 535 recalc(pcm, &sparams->avail_min); 536 rate->orig_avail_min = sparams->avail_min; 537 recalc(pcm, &sparams->start_threshold); 538 if (sparams->avail_min < 1) sparams->avail_min = 1; 539 if (sparams->start_threshold <= slave->buffer_size) { 540 if (sparams->start_threshold > (slave->buffer_size / sparams->avail_min) * sparams->avail_min) 541 sparams->start_threshold = (slave->buffer_size / sparams->avail_min) * sparams->avail_min; 542 } 543 if (sparams->stop_threshold >= params->boundary) { 544 sparams->stop_threshold = sparams->boundary; 545 } else { 546 recalc(pcm, &sparams->stop_threshold); 547 } 548 recalc(pcm, &sparams->silence_threshold); 549 if (sparams->silence_size >= params->boundary) { 550 sparams->silence_size = sparams->boundary; 551 } else { 552 recalc(pcm, &sparams->silence_size); 553 } 554 return snd_pcm_sw_params(slave, sparams); 555} 556 557static int snd_pcm_rate_init(snd_pcm_t *pcm) 558{ 559 snd_pcm_rate_t *rate = pcm->private_data; 560 561 if (rate->ops.reset) 562 rate->ops.reset(rate->obj); 563 rate->last_commit_ptr = 0; 564 rate->start_pending = 0; 565 return 0; 566} 567 568static void do_convert(const snd_pcm_channel_area_t *dst_areas, 569 snd_pcm_uframes_t dst_offset, unsigned int dst_frames, 570 const snd_pcm_channel_area_t *src_areas, 571 snd_pcm_uframes_t src_offset, unsigned int src_frames, 572 unsigned int channels, 573 snd_pcm_rate_t *rate) 574{ 575 const snd_pcm_channel_area_t *out_areas; 576 snd_pcm_uframes_t out_offset; 577 578 if (rate->dst_buf) { 579 out_areas = rate->dst_buf; 580 out_offset = 0; 581 } else { 582 out_areas = dst_areas; 583 out_offset = dst_offset; 584 } 585 586 if (rate->src_buf) { 587 snd_pcm_linear_convert(rate->src_buf, 0, 588 src_areas, src_offset, 589 channels, src_frames, 590 rate->src_conv_idx); 591 src_areas = rate->src_buf; 592 src_offset = 0; 593 } 594 595 if (rate->ops.convert) 596 rate->ops.convert(rate->obj, out_areas, out_offset, dst_frames, 597 src_areas, src_offset, src_frames); 598 else 599 rate->ops.convert_s16(rate->obj, 600 snd_pcm_channel_area_addr(out_areas, out_offset), 601 dst_frames, 602 snd_pcm_channel_area_addr(src_areas, src_offset), 603 src_frames); 604 if (rate->dst_buf) 605 snd_pcm_linear_convert(dst_areas, dst_offset, 606 rate->dst_buf, 0, 607 channels, dst_frames, 608 rate->dst_conv_idx); 609} 610 611static inline void 612snd_pcm_rate_write_areas1(snd_pcm_t *pcm, 613 const snd_pcm_channel_area_t *areas, 614 snd_pcm_uframes_t offset, 615 const snd_pcm_channel_area_t *slave_areas, 616 snd_pcm_uframes_t slave_offset) 617{ 618 snd_pcm_rate_t *rate = pcm->private_data; 619 do_convert(slave_areas, slave_offset, rate->gen.slave->period_size, 620 areas, offset, pcm->period_size, 621 pcm->channels, rate); 622} 623 624static inline void 625snd_pcm_rate_read_areas1(snd_pcm_t *pcm, 626 const snd_pcm_channel_area_t *areas, 627 snd_pcm_uframes_t offset, 628 const snd_pcm_channel_area_t *slave_areas, 629 snd_pcm_uframes_t slave_offset) 630{ 631 snd_pcm_rate_t *rate = pcm->private_data; 632 do_convert(areas, offset, pcm->period_size, 633 slave_areas, slave_offset, rate->gen.slave->period_size, 634 pcm->channels, rate); 635} 636 637static inline void snd_pcm_rate_sync_hwptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr) 638{ 639 snd_pcm_rate_t *rate; 640 snd_pcm_sframes_t slave_hw_ptr_diff; 641 snd_pcm_sframes_t last_slave_hw_ptr_frac; 642 643 if (pcm->stream != SND_PCM_STREAM_PLAYBACK) 644 return; 645 646 rate = pcm->private_data; 647 slave_hw_ptr_diff = pcm_frame_diff(slave_hw_ptr, rate->last_slave_hw_ptr, rate->gen.slave->boundary); 648 if (slave_hw_ptr_diff == 0) 649 return; 650 last_slave_hw_ptr_frac = rate->last_slave_hw_ptr % rate->gen.slave->period_size; 651 /* While handling fraction part fo slave period, rounded value will be 652 * introduced by input_frames(). 653 * To eliminate rounding issue on rate->hw_ptr, subtract last rounded 654 * value from rate->hw_ptr and add new rounded value of present 655 * slave_hw_ptr fraction part to rate->hw_ptr. Hence, 656 * rate->hw_ptr += [ (no. of updated slave periods * pcm rate period size) - 657 * fractional part of last_slave_hw_ptr rounded value + 658 * fractional part of updated slave hw ptr's rounded value ] 659 */ 660 rate->hw_ptr += ( 661 (((last_slave_hw_ptr_frac + slave_hw_ptr_diff) / rate->gen.slave->period_size) * pcm->period_size) - 662 rate->ops.input_frames(rate->obj, last_slave_hw_ptr_frac) + 663 rate->ops.input_frames(rate->obj, (last_slave_hw_ptr_frac + slave_hw_ptr_diff) % rate->gen.slave->period_size)); 664 rate->last_slave_hw_ptr = slave_hw_ptr; 665 666 rate->hw_ptr %= pcm->boundary; 667} 668 669static inline void snd_pcm_rate_sync_hwptr(snd_pcm_t *pcm) 670{ 671 snd_pcm_rate_t *rate = pcm->private_data; 672 snd_pcm_rate_sync_hwptr0(pcm, *rate->gen.slave->hw.ptr); 673} 674 675static int snd_pcm_rate_hwsync(snd_pcm_t *pcm) 676{ 677 snd_pcm_rate_t *rate = pcm->private_data; 678 int err = snd_pcm_hwsync(rate->gen.slave); 679 if (err < 0) 680 return err; 681 snd_pcm_rate_sync_hwptr(pcm); 682 return 0; 683} 684 685static snd_pcm_uframes_t snd_pcm_rate_playback_internal_delay(snd_pcm_t *pcm) 686{ 687 snd_pcm_rate_t *rate = pcm->private_data; 688 689 return pcm_frame_diff(rate->appl_ptr, rate->last_commit_ptr, pcm->boundary); 690} 691 692static int snd_pcm_rate_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 693{ 694 snd_pcm_rate_t *rate = pcm->private_data; 695 snd_pcm_sframes_t slave_delay; 696 int err; 697 698 snd_pcm_rate_hwsync(pcm); 699 700 err = snd_pcm_delay(rate->gen.slave, &slave_delay); 701 if (err < 0) { 702 return err; 703 } 704 705 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 706 *delayp = rate->ops.input_frames(rate->obj, slave_delay) 707 + snd_pcm_rate_playback_internal_delay(pcm); 708 } else { 709 *delayp = rate->ops.output_frames(rate->obj, slave_delay) 710 + snd_pcm_mmap_capture_delay(pcm); 711 } 712 return 0; 713} 714 715static int snd_pcm_rate_prepare(snd_pcm_t *pcm) 716{ 717 snd_pcm_rate_t *rate = pcm->private_data; 718 int err; 719 720 err = snd_pcm_prepare(rate->gen.slave); 721 if (err < 0) 722 return err; 723 *pcm->hw.ptr = 0; 724 *pcm->appl.ptr = 0; 725 rate->last_slave_hw_ptr = 0; 726 err = snd_pcm_rate_init(pcm); 727 if (err < 0) 728 return err; 729 return 0; 730} 731 732static int snd_pcm_rate_reset(snd_pcm_t *pcm) 733{ 734 snd_pcm_rate_t *rate = pcm->private_data; 735 int err; 736 err = snd_pcm_reset(rate->gen.slave); 737 if (err < 0) 738 return err; 739 *pcm->hw.ptr = 0; 740 *pcm->appl.ptr = 0; 741 rate->last_slave_hw_ptr = 0; 742 err = snd_pcm_rate_init(pcm); 743 if (err < 0) 744 return err; 745 return 0; 746} 747 748static snd_pcm_sframes_t snd_pcm_rate_rewindable(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 749{ 750 return 0; 751} 752 753static snd_pcm_sframes_t snd_pcm_rate_forwardable(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 754{ 755 return 0; 756} 757 758static snd_pcm_sframes_t snd_pcm_rate_rewind(snd_pcm_t *pcm ATTRIBUTE_UNUSED, 759 snd_pcm_uframes_t frames ATTRIBUTE_UNUSED) 760{ 761 return 0; 762} 763 764static snd_pcm_sframes_t snd_pcm_rate_forward(snd_pcm_t *pcm ATTRIBUTE_UNUSED, 765 snd_pcm_uframes_t frames ATTRIBUTE_UNUSED) 766{ 767 return 0; 768} 769 770static int snd_pcm_rate_commit_area(snd_pcm_t *pcm, snd_pcm_rate_t *rate, 771 snd_pcm_uframes_t appl_offset, 772 snd_pcm_uframes_t size ATTRIBUTE_UNUSED, 773 snd_pcm_uframes_t slave_size) 774{ 775 snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset; 776 const snd_pcm_channel_area_t *areas; 777 const snd_pcm_channel_area_t *slave_areas; 778 snd_pcm_uframes_t slave_offset, xfer; 779 snd_pcm_uframes_t slave_frames = ULONG_MAX; 780 snd_pcm_sframes_t result; 781 782 areas = snd_pcm_mmap_areas(pcm); 783 /* 784 * Because snd_pcm_rate_write_areas1() below will convert a full source period 785 * then there had better be a full period available in the current buffer. 786 */ 787 if (cont >= pcm->period_size) { 788 result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); 789 if (result < 0) 790 return result; 791 /* 792 * Because snd_pcm_rate_write_areas1() below will convert to a full slave period 793 * then there had better be a full slave period available in the slave buffer. 794 */ 795 if (slave_frames < rate->gen.slave->period_size) { 796 snd_pcm_rate_write_areas1(pcm, areas, appl_offset, rate->sareas, 0); 797 goto __partial; 798 } 799 snd_pcm_rate_write_areas1(pcm, areas, appl_offset, 800 slave_areas, slave_offset); 801 /* Only commit the requested slave_size, even if more was actually converted */ 802 result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, slave_size); 803 if (result < (snd_pcm_sframes_t)slave_size) { 804 if (result < 0) 805 return result; 806 result = snd_pcm_rewind(rate->gen.slave, result); 807 if (result < 0) 808 return result; 809 return 0; 810 } 811 } else { 812 snd_pcm_areas_copy(rate->pareas, 0, 813 areas, appl_offset, 814 pcm->channels, cont, 815 pcm->format); 816 snd_pcm_areas_copy(rate->pareas, cont, 817 areas, 0, 818 pcm->channels, pcm->period_size - cont, 819 pcm->format); 820 821 snd_pcm_rate_write_areas1(pcm, rate->pareas, 0, rate->sareas, 0); 822 823 /* ok, commit first fragment */ 824 result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); 825 if (result < 0) 826 return result; 827 __partial: 828 cont = slave_frames; 829 if (cont > slave_size) 830 cont = slave_size; 831 snd_pcm_areas_copy(slave_areas, slave_offset, 832 rate->sareas, 0, 833 pcm->channels, cont, 834 rate->gen.slave->format); 835 result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont); 836 if (result < (snd_pcm_sframes_t)cont) { 837 if (result < 0) 838 return result; 839 result = snd_pcm_rewind(rate->gen.slave, result); 840 if (result < 0) 841 return result; 842 return 0; 843 } 844 xfer = cont; 845 846 if (xfer == slave_size) 847 goto commit_done; 848 849 /* commit second fragment */ 850 cont = slave_size - cont; 851 slave_frames = cont; 852 result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); 853 if (result < 0) 854 return result; 855#if 0 856 if (slave_offset) { 857 SNDERR("non-zero slave_offset %ld", slave_offset); 858 return -EIO; 859 } 860#endif 861 snd_pcm_areas_copy(slave_areas, slave_offset, 862 rate->sareas, xfer, 863 pcm->channels, cont, 864 rate->gen.slave->format); 865 result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont); 866 if (result < (snd_pcm_sframes_t)cont) { 867 if (result < 0) 868 return result; 869 result = snd_pcm_rewind(rate->gen.slave, result + xfer); 870 if (result < 0) 871 return result; 872 return 0; 873 } 874 } 875 876 commit_done: 877 if (rate->start_pending) { 878 /* we have pending start-trigger. let's issue it now */ 879 snd_pcm_start(rate->gen.slave); 880 rate->start_pending = 0; 881 } 882 return 1; 883} 884 885static int snd_pcm_rate_commit_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t appl_offset) 886{ 887 snd_pcm_rate_t *rate = pcm->private_data; 888 889 return snd_pcm_rate_commit_area(pcm, rate, appl_offset, pcm->period_size, 890 rate->gen.slave->period_size); 891} 892 893static int snd_pcm_rate_grab_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t hw_offset) 894{ 895 snd_pcm_rate_t *rate = pcm->private_data; 896 snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset; 897 const snd_pcm_channel_area_t *areas; 898 const snd_pcm_channel_area_t *slave_areas; 899 snd_pcm_uframes_t slave_offset, xfer; 900 snd_pcm_uframes_t slave_frames = ULONG_MAX; 901 snd_pcm_sframes_t result; 902 903 areas = snd_pcm_mmap_areas(pcm); 904 if (cont >= pcm->period_size) { 905 result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); 906 if (result < 0) 907 return result; 908 if (slave_frames < rate->gen.slave->period_size) 909 goto __partial; 910 snd_pcm_rate_read_areas1(pcm, areas, hw_offset, 911 slave_areas, slave_offset); 912 result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, rate->gen.slave->period_size); 913 if (result < (snd_pcm_sframes_t)rate->gen.slave->period_size) { 914 if (result < 0) 915 return result; 916 result = snd_pcm_rewind(rate->gen.slave, result); 917 if (result < 0) 918 return result; 919 return 0; 920 } 921 } else { 922 /* ok, grab first fragment */ 923 result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); 924 if (result < 0) 925 return result; 926 __partial: 927 cont = slave_frames; 928 if (cont > rate->gen.slave->period_size) 929 cont = rate->gen.slave->period_size; 930 snd_pcm_areas_copy(rate->sareas, 0, 931 slave_areas, slave_offset, 932 pcm->channels, cont, 933 rate->gen.slave->format); 934 result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont); 935 if (result < (snd_pcm_sframes_t)cont) { 936 if (result < 0) 937 return result; 938 result = snd_pcm_rewind(rate->gen.slave, result); 939 if (result < 0) 940 return result; 941 return 0; 942 } 943 xfer = cont; 944 945 if (xfer == rate->gen.slave->period_size) 946 goto __transfer; 947 948 /* grab second fragment */ 949 cont = rate->gen.slave->period_size - cont; 950 slave_frames = cont; 951 result = snd_pcm_mmap_begin(rate->gen.slave, &slave_areas, &slave_offset, &slave_frames); 952 if (result < 0) 953 return result; 954#if 0 955 if (slave_offset) { 956 SNDERR("non-zero slave_offset %ld", slave_offset); 957 return -EIO; 958 } 959#endif 960 snd_pcm_areas_copy(rate->sareas, xfer, 961 slave_areas, slave_offset, 962 pcm->channels, cont, 963 rate->gen.slave->format); 964 result = snd_pcm_mmap_commit(rate->gen.slave, slave_offset, cont); 965 if (result < (snd_pcm_sframes_t)cont) { 966 if (result < 0) 967 return result; 968 result = snd_pcm_rewind(rate->gen.slave, result + xfer); 969 if (result < 0) 970 return result; 971 return 0; 972 } 973 974 __transfer: 975 cont = pcm->buffer_size - hw_offset; 976 if (cont >= pcm->period_size) { 977 snd_pcm_rate_read_areas1(pcm, areas, hw_offset, 978 rate->sareas, 0); 979 } else { 980 snd_pcm_rate_read_areas1(pcm, 981 rate->pareas, 0, 982 rate->sareas, 0); 983 snd_pcm_areas_copy(areas, hw_offset, 984 rate->pareas, 0, 985 pcm->channels, cont, 986 pcm->format); 987 snd_pcm_areas_copy(areas, 0, 988 rate->pareas, cont, 989 pcm->channels, pcm->period_size - cont, 990 pcm->format); 991 } 992 } 993 return 1; 994} 995 996static int snd_pcm_rate_sync_playback_area(snd_pcm_t *pcm, snd_pcm_uframes_t appl_ptr) 997{ 998 snd_pcm_rate_t *rate = pcm->private_data; 999 snd_pcm_t *slave = rate->gen.slave; 1000 snd_pcm_uframes_t xfer; 1001 snd_pcm_sframes_t slave_size; 1002 int err; 1003 1004 slave_size = snd_pcm_avail_update(slave); 1005 if (slave_size < 0) 1006 return slave_size; 1007 1008 xfer = pcm_frame_diff(appl_ptr, rate->last_commit_ptr, pcm->boundary); 1009 while (xfer >= pcm->period_size && 1010 (snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) { 1011 err = snd_pcm_rate_commit_next_period(pcm, rate->last_commit_ptr % pcm->buffer_size); 1012 if (err == 0) 1013 break; 1014 if (err < 0) 1015 return err; 1016 xfer -= pcm->period_size; 1017 slave_size -= rate->gen.slave->period_size; 1018 rate->last_commit_ptr += pcm->period_size; 1019 if (rate->last_commit_ptr >= pcm->boundary) 1020 rate->last_commit_ptr -= pcm->boundary; 1021 } 1022 return 0; 1023} 1024 1025static snd_pcm_sframes_t snd_pcm_rate_mmap_commit(snd_pcm_t *pcm, 1026 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, 1027 snd_pcm_uframes_t size) 1028{ 1029 snd_pcm_rate_t *rate = pcm->private_data; 1030 int err; 1031 1032 if (size == 0) 1033 return 0; 1034 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 1035 err = snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr + size); 1036 if (err < 0) 1037 return err; 1038 } 1039 snd_pcm_mmap_appl_forward(pcm, size); 1040 return size; 1041} 1042 1043static snd_pcm_sframes_t snd_pcm_rate_avail_update_capture(snd_pcm_t *pcm, 1044 snd_pcm_sframes_t slave_size) 1045{ 1046 snd_pcm_rate_t *rate = pcm->private_data; 1047 snd_pcm_t *slave = rate->gen.slave; 1048 snd_pcm_uframes_t xfer, hw_offset, size; 1049 1050 xfer = snd_pcm_mmap_capture_avail(pcm); 1051 size = pcm->buffer_size - xfer; 1052 hw_offset = snd_pcm_mmap_hw_offset(pcm); 1053 while (size >= pcm->period_size && 1054 (snd_pcm_uframes_t)slave_size >= slave->period_size) { 1055 int err = snd_pcm_rate_grab_next_period(pcm, hw_offset); 1056 if (err < 0) 1057 return err; 1058 if (err == 0) 1059 return (snd_pcm_sframes_t)xfer; 1060 xfer += pcm->period_size; 1061 size -= pcm->period_size; 1062 slave_size -= slave->period_size; 1063 hw_offset += pcm->period_size; 1064 hw_offset %= pcm->buffer_size; 1065 snd_pcm_mmap_hw_forward(pcm, pcm->period_size); 1066 } 1067 return (snd_pcm_sframes_t)xfer; 1068} 1069 1070static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm) 1071{ 1072 snd_pcm_rate_t *rate = pcm->private_data; 1073 snd_pcm_sframes_t slave_size; 1074 1075 slave_size = snd_pcm_avail_update(rate->gen.slave); 1076 if (slave_size < 0) 1077 return slave_size; 1078 1079 if (pcm->stream == SND_PCM_STREAM_CAPTURE) 1080 return snd_pcm_rate_avail_update_capture(pcm, slave_size); 1081 1082 snd_pcm_rate_sync_hwptr(pcm); 1083 snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr); 1084 return snd_pcm_mmap_avail(pcm); 1085} 1086 1087static int snd_pcm_rate_htimestamp(snd_pcm_t *pcm, 1088 snd_pcm_uframes_t *avail, 1089 snd_htimestamp_t *tstamp) 1090{ 1091 snd_pcm_rate_t *rate = pcm->private_data; 1092 snd_pcm_sframes_t avail1; 1093 snd_pcm_uframes_t tmp; 1094 int ok = 0, err; 1095 1096 while (1) { 1097 /* the position is from this plugin itself */ 1098 avail1 = snd_pcm_avail_update(pcm); 1099 if (avail1 < 0) 1100 return avail1; 1101 if (ok && (snd_pcm_uframes_t)avail1 == *avail) 1102 break; 1103 *avail = avail1; 1104 /* timestamp is taken from the slave PCM */ 1105 err = snd_pcm_htimestamp(rate->gen.slave, &tmp, tstamp); 1106 if (err < 0) 1107 return err; 1108 ok = 1; 1109 } 1110 return 0; 1111} 1112 1113static int snd_pcm_rate_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) 1114{ 1115 snd_pcm_rate_t *rate = pcm->private_data; 1116 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 1117 /* Try to sync as much as possible */ 1118 snd_pcm_rate_hwsync(pcm); 1119 snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr); 1120 } 1121 return snd_pcm_poll_descriptors_revents(rate->gen.slave, pfds, nfds, revents); 1122} 1123 1124/* locking */ 1125static int snd_pcm_rate_drain(snd_pcm_t *pcm) 1126{ 1127 snd_pcm_rate_t *rate = pcm->private_data; 1128 1129 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 1130 /* commit the remaining fraction (if any) */ 1131 snd_pcm_uframes_t size, ofs, saved_avail_min; 1132 snd_pcm_sw_params_t sw_params; 1133 int commit_err = 0; 1134 1135 __snd_pcm_lock(pcm); 1136 /* temporarily set avail_min to one */ 1137 sw_params = rate->sw_params; 1138 saved_avail_min = sw_params.avail_min; 1139 sw_params.avail_min = 1; 1140 snd_pcm_sw_params(rate->gen.slave, &sw_params); 1141 1142 size = pcm_frame_diff(rate->appl_ptr, rate->last_commit_ptr, pcm->boundary); 1143 ofs = rate->last_commit_ptr % pcm->buffer_size; 1144 while (size > 0) { 1145 snd_pcm_uframes_t psize, spsize; 1146 int err; 1147 1148 err = __snd_pcm_wait_in_lock(rate->gen.slave, SND_PCM_WAIT_DRAIN); 1149 if (err < 0) 1150 break; 1151 if (size > pcm->period_size) { 1152 psize = pcm->period_size; 1153 spsize = rate->gen.slave->period_size; 1154 } else { 1155 psize = size; 1156 spsize = rate->ops.output_frames(rate->obj, size); 1157 if (! spsize) 1158 break; 1159 } 1160 commit_err = snd_pcm_rate_commit_area(pcm, rate, ofs, 1161 psize, spsize); 1162 if (commit_err == 1) { 1163 rate->last_commit_ptr += psize; 1164 if (rate->last_commit_ptr >= pcm->boundary) 1165 rate->last_commit_ptr -= pcm->boundary; 1166 } else if (commit_err == 0) { 1167 if (pcm->mode & SND_PCM_NONBLOCK) { 1168 commit_err = -EAGAIN; 1169 break; 1170 } 1171 continue; 1172 } else 1173 break; 1174 1175 ofs = (ofs + psize) % pcm->buffer_size; 1176 size -= psize; 1177 } 1178 sw_params.avail_min = saved_avail_min; 1179 snd_pcm_sw_params(rate->gen.slave, &sw_params); 1180 __snd_pcm_unlock(pcm); 1181 if (commit_err < 0) 1182 return commit_err; 1183 } 1184 return snd_pcm_drain(rate->gen.slave); 1185} 1186 1187static snd_pcm_state_t snd_pcm_rate_state(snd_pcm_t *pcm) 1188{ 1189 snd_pcm_rate_t *rate = pcm->private_data; 1190 if (rate->start_pending) /* pseudo-state */ 1191 return SND_PCM_STATE_RUNNING; 1192 return snd_pcm_state(rate->gen.slave); 1193} 1194 1195 1196static int snd_pcm_rate_start(snd_pcm_t *pcm) 1197{ 1198 snd_pcm_rate_t *rate = pcm->private_data; 1199 snd_pcm_sframes_t avail; 1200 1201 if (pcm->stream == SND_PCM_STREAM_CAPTURE) 1202 return snd_pcm_start(rate->gen.slave); 1203 1204 if (snd_pcm_state(rate->gen.slave) != SND_PCM_STATE_PREPARED) 1205 return -EBADFD; 1206 1207 gettimestamp(&rate->trigger_tstamp, pcm->tstamp_type); 1208 1209 avail = snd_pcm_mmap_playback_hw_avail(rate->gen.slave); 1210 if (avail < 0) /* can't happen on healthy drivers */ 1211 return -EBADFD; 1212 1213 if (avail == 0) { 1214 /* postpone the trigger since we have no data committed yet */ 1215 rate->start_pending = 1; 1216 return 0; 1217 } 1218 rate->start_pending = 0; 1219 return snd_pcm_start(rate->gen.slave); 1220} 1221 1222static int snd_pcm_rate_status(snd_pcm_t *pcm, snd_pcm_status_t * status) 1223{ 1224 snd_pcm_rate_t *rate = pcm->private_data; 1225 snd_pcm_sframes_t err; 1226 1227 err = snd_pcm_status(rate->gen.slave, status); 1228 if (err < 0) 1229 return err; 1230 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 1231 if (rate->start_pending) 1232 status->state = SND_PCM_STATE_RUNNING; 1233 status->trigger_tstamp = rate->trigger_tstamp; 1234 } 1235 snd_pcm_rate_sync_hwptr0(pcm, status->hw_ptr); 1236 status->appl_ptr = *pcm->appl.ptr; 1237 status->hw_ptr = *pcm->hw.ptr; 1238 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 1239 status->delay = rate->ops.input_frames(rate->obj, status->delay) 1240 + snd_pcm_rate_playback_internal_delay(pcm); 1241 status->avail = snd_pcm_mmap_playback_avail(pcm); 1242 status->avail_max = rate->ops.input_frames(rate->obj, status->avail_max); 1243 } else { 1244 status->delay = rate->ops.output_frames(rate->obj, status->delay) 1245 + snd_pcm_mmap_capture_delay(pcm); 1246 status->avail = snd_pcm_mmap_capture_avail(pcm); 1247 status->avail_max = rate->ops.output_frames(rate->obj, status->avail_max); 1248 } 1249 return 0; 1250} 1251 1252static void snd_pcm_rate_dump(snd_pcm_t *pcm, snd_output_t *out) 1253{ 1254 snd_pcm_rate_t *rate = pcm->private_data; 1255 if (rate->sformat == SND_PCM_FORMAT_UNKNOWN) 1256 snd_output_printf(out, "Rate conversion PCM (%d)\n", 1257 rate->srate); 1258 else 1259 snd_output_printf(out, "Rate conversion PCM (%d, sformat=%s)\n", 1260 rate->srate, 1261 snd_pcm_format_name(rate->sformat)); 1262 if (rate->ops.dump) 1263 rate->ops.dump(rate->obj, out); 1264 snd_output_printf(out, "Protocol version: %x\n", rate->plugin_version); 1265 if (pcm->setup) { 1266 snd_output_printf(out, "Its setup is:\n"); 1267 snd_pcm_dump_setup(pcm, out); 1268 } 1269 snd_output_printf(out, "Slave: "); 1270 snd_pcm_dump(rate->gen.slave, out); 1271} 1272 1273static int snd_pcm_rate_close(snd_pcm_t *pcm) 1274{ 1275 snd_pcm_rate_t *rate = pcm->private_data; 1276 1277 if (rate->ops.close) 1278 rate->ops.close(rate->obj); 1279 if (rate->open_func) 1280 snd_dlobj_cache_put(rate->open_func); 1281 return snd_pcm_generic_close(pcm); 1282} 1283 1284/** 1285 * \brief Convert rate pcm frames to corresponding rate slave pcm frames 1286 * \param pcm PCM handle 1287 * \param frames Frames to be converted to slave frames 1288 * \retval Corresponding slave frames 1289*/ 1290static snd_pcm_uframes_t snd_pcm_rate_slave_frames(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 1291{ 1292 snd_pcm_uframes_t sframes; 1293 snd_pcm_rate_t *rate = pcm->private_data; 1294 1295 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) 1296 sframes = rate->ops.output_frames(rate->obj, frames); 1297 else 1298 sframes = rate->ops.input_frames(rate->obj, frames); 1299 1300 return sframes; 1301} 1302 1303static int snd_pcm_rate_may_wait_for_avail_min(snd_pcm_t *pcm, 1304 snd_pcm_uframes_t avail) 1305{ 1306 return snd_pcm_plugin_may_wait_for_avail_min_conv(pcm, avail, 1307 snd_pcm_rate_slave_frames); 1308} 1309 1310static const snd_pcm_fast_ops_t snd_pcm_rate_fast_ops = { 1311 .status = snd_pcm_rate_status, 1312 .state = snd_pcm_rate_state, 1313 .hwsync = snd_pcm_rate_hwsync, 1314 .delay = snd_pcm_rate_delay, 1315 .prepare = snd_pcm_rate_prepare, 1316 .reset = snd_pcm_rate_reset, 1317 .start = snd_pcm_rate_start, 1318 .drop = snd_pcm_generic_drop, 1319 .drain = snd_pcm_rate_drain, 1320 .pause = snd_pcm_generic_pause, 1321 .rewindable = snd_pcm_rate_rewindable, 1322 .rewind = snd_pcm_rate_rewind, 1323 .forwardable = snd_pcm_rate_forwardable, 1324 .forward = snd_pcm_rate_forward, 1325 .resume = snd_pcm_generic_resume, 1326 .writei = snd_pcm_mmap_writei, 1327 .writen = snd_pcm_mmap_writen, 1328 .readi = snd_pcm_mmap_readi, 1329 .readn = snd_pcm_mmap_readn, 1330 .avail_update = snd_pcm_rate_avail_update, 1331 .mmap_commit = snd_pcm_rate_mmap_commit, 1332 .htimestamp = snd_pcm_rate_htimestamp, 1333 .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, 1334 .poll_descriptors = snd_pcm_generic_poll_descriptors, 1335 .poll_revents = snd_pcm_rate_poll_revents, 1336 .may_wait_for_avail_min = snd_pcm_rate_may_wait_for_avail_min, 1337}; 1338 1339static const snd_pcm_ops_t snd_pcm_rate_ops = { 1340 .close = snd_pcm_rate_close, 1341 .info = snd_pcm_generic_info, 1342 .hw_refine = snd_pcm_rate_hw_refine, 1343 .hw_params = snd_pcm_rate_hw_params, 1344 .hw_free = snd_pcm_rate_hw_free, 1345 .sw_params = snd_pcm_rate_sw_params, 1346 .channel_info = snd_pcm_generic_channel_info, 1347 .dump = snd_pcm_rate_dump, 1348 .nonblock = snd_pcm_generic_nonblock, 1349 .async = snd_pcm_generic_async, 1350 .mmap = snd_pcm_generic_mmap, 1351 .munmap = snd_pcm_generic_munmap, 1352 .query_chmaps = snd_pcm_generic_query_chmaps, 1353 .get_chmap = snd_pcm_generic_get_chmap, 1354 .set_chmap = snd_pcm_generic_set_chmap, 1355}; 1356 1357/** 1358 * \brief Get a default converter string 1359 * \param root Root configuration node 1360 * \retval A const config item if found, or NULL 1361 */ 1362const snd_config_t *snd_pcm_rate_get_default_converter(snd_config_t *root) 1363{ 1364 snd_config_t *n; 1365 /* look for default definition */ 1366 if (snd_config_search(root, "defaults.pcm.rate_converter", &n) >= 0) 1367 return n; 1368 return NULL; 1369} 1370 1371static void rate_initial_setup(snd_pcm_rate_t *rate) 1372{ 1373 if (rate->plugin_version == SND_PCM_RATE_PLUGIN_VERSION) 1374 rate->plugin_version = rate->ops.version; 1375 1376 if (rate->plugin_version >= 0x010002 && 1377 rate->ops.get_supported_rates) 1378 rate->ops.get_supported_rates(rate->obj, 1379 &rate->rate_min, 1380 &rate->rate_max); 1381 1382 if (rate->plugin_version >= 0x010003 && 1383 rate->ops.get_supported_formats) { 1384 rate->ops.get_supported_formats(rate->obj, 1385 &rate->in_formats, 1386 &rate->out_formats, 1387 &rate->format_flags); 1388 } else if (!rate->ops.convert && rate->ops.convert_s16) { 1389 rate->in_formats = rate->out_formats = 1390 1ULL << SND_PCM_FORMAT_S16; 1391 rate->format_flags = SND_PCM_RATE_FLAG_INTERLEAVED; 1392 } 1393} 1394 1395#ifdef PIC 1396static int is_builtin_plugin(const char *type) 1397{ 1398 return strcmp(type, "linear") == 0; 1399} 1400 1401static const char *const default_rate_plugins[] = { 1402 "speexrate", "linear", NULL 1403}; 1404 1405static int rate_open_func(snd_pcm_rate_t *rate, const char *type, const snd_config_t *converter_conf, int verbose) 1406{ 1407 char open_name[64], open_conf_name[64], lib_name[64], *lib = NULL; 1408 snd_pcm_rate_open_func_t open_func; 1409 snd_pcm_rate_open_conf_func_t open_conf_func; 1410 int err; 1411 1412 snprintf(open_name, sizeof(open_name), "_snd_pcm_rate_%s_open", type); 1413 snprintf(open_conf_name, sizeof(open_conf_name), "_snd_pcm_rate_%s_open_conf", type); 1414 if (!is_builtin_plugin(type)) { 1415 snprintf(lib_name, sizeof(lib_name), 1416 "libasound_module_rate_%s.so", type); 1417 lib = lib_name; 1418 } 1419 1420 open_conf_func = snd_dlobj_cache_get(lib, open_conf_name, NULL, verbose && converter_conf != NULL); 1421 if (open_conf_func) { 1422 err = open_conf_func(SND_PCM_RATE_PLUGIN_VERSION, 1423 &rate->obj, &rate->ops, converter_conf); 1424 if (!err) { 1425 rate->open_func = open_conf_func; 1426 return 0; 1427 } else { 1428 snd_dlobj_cache_put(open_conf_func); 1429 return err; 1430 } 1431 } 1432 1433 open_func = snd_dlobj_cache_get(lib, open_name, NULL, verbose); 1434 if (!open_func) 1435 return -ENOENT; 1436 1437 rate->open_func = open_func; 1438 1439 err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops); 1440 if (!err) 1441 return 0; 1442 1443 /* try to open with the old protocol version */ 1444 rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION_OLD; 1445 err = open_func(SND_PCM_RATE_PLUGIN_VERSION_OLD, 1446 &rate->obj, &rate->ops); 1447 if (!err) 1448 return 0; 1449 1450 snd_dlobj_cache_put(open_func); 1451 rate->open_func = NULL; 1452 return err; 1453} 1454#endif 1455 1456/* 1457 * If the conf is an array of alternatives then the id of 1458 * the first element will be "0" (or maybe NULL). Otherwise assume it is 1459 * a structure. 1460 */ 1461static int is_string_array(const snd_config_t *conf) 1462{ 1463 snd_config_iterator_t i; 1464 1465 if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) 1466 return 0; 1467 1468 i = snd_config_iterator_first(conf); 1469 if (i && i != snd_config_iterator_end(conf)) { 1470 snd_config_t *n = snd_config_iterator_entry(i); 1471 const char *id; 1472 if (snd_config_get_id(n, &id) < 0) 1473 return 0; 1474 if (id && strcmp(id, "0") != 0) 1475 return 0; 1476 } 1477 1478 return 1; 1479} 1480 1481/** 1482 * \brief Creates a new rate PCM 1483 * \param pcmp Returns created PCM handle 1484 * \param name Name of PCM 1485 * \param sformat Slave format 1486 * \param srate Slave rate 1487 * \param converter SRC type string node 1488 * \param slave Slave PCM handle 1489 * \param close_slave When set, the slave PCM handle is closed with copy PCM 1490 * \retval zero on success otherwise a negative error code 1491 * \warning Using of this function might be dangerous in the sense 1492 * of compatibility reasons. The prototype might be freely 1493 * changed in future. 1494 */ 1495int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, 1496 snd_pcm_format_t sformat, unsigned int srate, 1497 const snd_config_t *converter, 1498 snd_pcm_t *slave, int close_slave) 1499{ 1500 snd_pcm_t *pcm; 1501 snd_pcm_rate_t *rate; 1502 const char *type = NULL; 1503 int err; 1504#ifndef PIC 1505 snd_pcm_rate_open_func_t open_func; 1506 extern int SND_PCM_RATE_PLUGIN_ENTRY(linear) (unsigned int version, void **objp, snd_pcm_rate_ops_t *ops); 1507#endif 1508 1509 assert(pcmp && slave); 1510 if (sformat != SND_PCM_FORMAT_UNKNOWN && 1511 snd_pcm_format_linear(sformat) != 1) 1512 return -EINVAL; 1513 rate = calloc(1, sizeof(snd_pcm_rate_t)); 1514 if (!rate) { 1515 return -ENOMEM; 1516 } 1517 rate->gen.slave = slave; 1518 rate->gen.close_slave = close_slave; 1519 rate->srate = srate; 1520 rate->sformat = sformat; 1521 1522 rate->rate_min = SND_PCM_PLUGIN_RATE_MIN; 1523 rate->rate_max = SND_PCM_PLUGIN_RATE_MAX; 1524 rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION; 1525 1526 err = snd_pcm_new(&pcm, SND_PCM_TYPE_RATE, name, slave->stream, slave->mode); 1527 if (err < 0) { 1528 free(rate); 1529 return err; 1530 } 1531 1532#ifdef PIC 1533 err = -ENOENT; 1534 if (!converter) { 1535 const char *const *types; 1536 for (types = default_rate_plugins; *types; types++) { 1537 err = rate_open_func(rate, *types, NULL, 0); 1538 if (!err) { 1539 type = *types; 1540 break; 1541 } 1542 } 1543 } else if (!snd_config_get_string(converter, &type)) 1544 err = rate_open_func(rate, type, NULL, 1); 1545 else if (is_string_array(converter)) { 1546 snd_config_iterator_t i, next; 1547 snd_config_for_each(i, next, converter) { 1548 snd_config_t *n = snd_config_iterator_entry(i); 1549 if (snd_config_get_string(n, &type) < 0) 1550 break; 1551 err = rate_open_func(rate, type, NULL, 0); 1552 if (!err) 1553 break; 1554 } 1555 } else if (snd_config_get_type(converter) == SND_CONFIG_TYPE_COMPOUND) { 1556 snd_config_iterator_t i, next; 1557 snd_config_for_each(i, next, converter) { 1558 snd_config_t *n = snd_config_iterator_entry(i); 1559 const char *id; 1560 if (snd_config_get_id(n, &id) < 0) 1561 continue; 1562 if (strcmp(id, "name") != 0) 1563 continue; 1564 snd_config_get_string(n, &type); 1565 break; 1566 } 1567 if (!type) { 1568 SNDERR("No name given for rate converter"); 1569 snd_pcm_free(pcm); 1570 free(rate); 1571 return -EINVAL; 1572 } 1573 err = rate_open_func(rate, type, converter, 1); 1574 } else { 1575 SNDERR("Invalid type for rate converter"); 1576 snd_pcm_free(pcm); 1577 free(rate); 1578 return -EINVAL; 1579 } 1580 if (err < 0) { 1581 SNDERR("Cannot find rate converter"); 1582 snd_pcm_free(pcm); 1583 free(rate); 1584 return -ENOENT; 1585 } 1586#else 1587 type = "linear"; 1588 open_func = SND_PCM_RATE_PLUGIN_ENTRY(linear); 1589 err = open_func(SND_PCM_RATE_PLUGIN_VERSION, &rate->obj, &rate->ops); 1590 if (err < 0) { 1591 snd_pcm_free(pcm); 1592 free(rate); 1593 return err; 1594 } 1595#endif 1596 1597 if (! rate->ops.init || ! (rate->ops.convert || rate->ops.convert_s16) || 1598 ! rate->ops.input_frames || ! rate->ops.output_frames) { 1599 SNDERR("Inproper rate plugin %s initialization", type); 1600 snd_pcm_free(pcm); 1601 free(rate); 1602 return err; 1603 } 1604 1605 rate_initial_setup(rate); 1606 1607 pcm->ops = &snd_pcm_rate_ops; 1608 pcm->fast_ops = &snd_pcm_rate_fast_ops; 1609 pcm->private_data = rate; 1610 pcm->poll_fd = slave->poll_fd; 1611 pcm->poll_events = slave->poll_events; 1612 pcm->mmap_rw = 1; 1613 pcm->tstamp_type = slave->tstamp_type; 1614 snd_pcm_set_hw_ptr(pcm, &rate->hw_ptr, -1, 0); 1615 snd_pcm_set_appl_ptr(pcm, &rate->appl_ptr, -1, 0); 1616 *pcmp = pcm; 1617 1618 return 0; 1619} 1620 1621/*! \page pcm_plugins 1622 1623\section pcm_plugins_rate Plugin: Rate 1624 1625This plugin converts a stream rate. The input and output formats must be linear. 1626 1627\code 1628pcm.name { 1629 type rate # Rate PCM 1630 slave STR # Slave name 1631 # or 1632 slave { # Slave definition 1633 pcm STR # Slave PCM name 1634 # or 1635 pcm { } # Slave PCM definition 1636 rate INT # Slave rate 1637 [format STR] # Slave format 1638 } 1639 converter STR # optional 1640 # or 1641 converter [ STR1 STR2 ... ] # optional 1642 # Converter type, default is taken from 1643 # defaults.pcm.rate_converter 1644 # or 1645 converter { # optional 1646 name STR # Convertor type 1647 xxx yyy # optional convertor-specific configuration 1648 } 1649} 1650\endcode 1651 1652\subsection pcm_plugins_rate_funcref Function reference 1653 1654<UL> 1655 <LI>snd_pcm_rate_open() 1656 <LI>_snd_pcm_rate_open() 1657</UL> 1658 1659*/ 1660 1661/** 1662 * \brief Creates a new rate PCM 1663 * \param pcmp Returns created PCM handle 1664 * \param name Name of PCM 1665 * \param root Root configuration node 1666 * \param conf Configuration node with rate PCM description 1667 * \param stream Stream type 1668 * \param mode Stream mode 1669 * \retval zero on success otherwise a negative error code 1670 * \warning Using of this function might be dangerous in the sense 1671 * of compatibility reasons. The prototype might be freely 1672 * changed in future. 1673 */ 1674int _snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, 1675 snd_config_t *root, snd_config_t *conf, 1676 snd_pcm_stream_t stream, int mode) 1677{ 1678 snd_config_iterator_t i, next; 1679 int err; 1680 snd_pcm_t *spcm; 1681 snd_config_t *slave = NULL, *sconf; 1682 snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN; 1683 int srate = -1; 1684 const snd_config_t *converter = NULL; 1685 1686 snd_config_for_each(i, next, conf) { 1687 snd_config_t *n = snd_config_iterator_entry(i); 1688 const char *id; 1689 if (snd_config_get_id(n, &id) < 0) 1690 continue; 1691 if (snd_pcm_conf_generic_id(id)) 1692 continue; 1693 if (strcmp(id, "slave") == 0) { 1694 slave = n; 1695 continue; 1696 } 1697 if (strcmp(id, "converter") == 0) { 1698 converter = n; 1699 continue; 1700 } 1701 SNDERR("Unknown field %s", id); 1702 return -EINVAL; 1703 } 1704 if (!slave) { 1705 SNDERR("slave is not defined"); 1706 return -EINVAL; 1707 } 1708 1709 err = snd_pcm_slave_conf(root, slave, &sconf, 2, 1710 SND_PCM_HW_PARAM_FORMAT, 0, &sformat, 1711 SND_PCM_HW_PARAM_RATE, SCONF_MANDATORY, &srate); 1712 if (err < 0) 1713 return err; 1714 if (sformat != SND_PCM_FORMAT_UNKNOWN && 1715 snd_pcm_format_linear(sformat) != 1) { 1716 snd_config_delete(sconf); 1717 SNDERR("slave format is not linear"); 1718 return -EINVAL; 1719 } 1720 err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); 1721 snd_config_delete(sconf); 1722 if (err < 0) 1723 return err; 1724 err = snd_pcm_rate_open(pcmp, name, sformat, (unsigned int) srate, 1725 converter, spcm, 1); 1726 if (err < 0) 1727 snd_pcm_close(spcm); 1728 return err; 1729} 1730#ifndef DOC_HIDDEN 1731SND_DLSYM_BUILD_VERSION(_snd_pcm_rate_open, SND_PCM_DLSYM_VERSION); 1732#endif 1733