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