1 // SPDX-License-Identifier: LGPL-2.0+ 2 /* 3 * PCM Plug-In shared (kernel/library) code 4 * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> 5 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> 6 */ 7 8 #if 0 9 #define PLUGIN_DEBUG 10 #endif 11 12 #include <linux/slab.h> 13 #include <linux/time.h> 14 #include <linux/vmalloc.h> 15 #include <sound/core.h> 16 #include <sound/pcm.h> 17 #include <sound/pcm_params.h> 18 #include "pcm_plugin.h" 19 20 #define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first) 21 #define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last) 22 23 /* 24 * because some cards might have rates "very close", we ignore 25 * all "resampling" requests within +-5% 26 */ 27 static int rate_match(unsigned int src_rate, unsigned int dst_rate) 28 { 29 unsigned int low = (src_rate * 95) / 100; 30 unsigned int high = (src_rate * 105) / 100; 31 return dst_rate >= low && dst_rate <= high; 32 } 33 34 static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames) 35 { 36 struct snd_pcm_plugin_format *format; 37 ssize_t width; 38 size_t size; 39 unsigned int channel; 40 struct snd_pcm_plugin_channel *c; 41 42 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) { 43 format = &plugin->src_format; 44 } else { 45 format = &plugin->dst_format; 46 } 47 width = snd_pcm_format_physical_width(format->format); 48 if (width < 0) 49 return width; 50 size = array3_size(frames, format->channels, width); 51 /* check for too large period size once again */ 52 if (size > 1024 * 1024) 53 return -ENOMEM; 54 if (snd_BUG_ON(size % 8)) 55 return -ENXIO; 56 size /= 8; 57 if (plugin->buf_frames < frames) { 58 kvfree(plugin->buf); 59 plugin->buf = kvzalloc(size, GFP_KERNEL); 60 plugin->buf_frames = frames; 61 } 62 if (!plugin->buf) { 63 plugin->buf_frames = 0; 64 return -ENOMEM; 65 } 66 c = plugin->buf_channels; 67 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { 68 for (channel = 0; channel < format->channels; channel++, c++) { 69 c->frames = frames; 70 c->enabled = 1; 71 c->wanted = 0; 72 c->area.addr = plugin->buf; 73 c->area.first = channel * width; 74 c->area.step = format->channels * width; 75 } 76 } else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { 77 if (snd_BUG_ON(size % format->channels)) 78 return -EINVAL; 79 size /= format->channels; 80 for (channel = 0; channel < format->channels; channel++, c++) { 81 c->frames = frames; 82 c->enabled = 1; 83 c->wanted = 0; 84 c->area.addr = plugin->buf + (channel * size); 85 c->area.first = 0; 86 c->area.step = width; 87 } 88 } else 89 return -EINVAL; 90 return 0; 91 } 92 93 int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames) 94 { 95 int err; 96 if (snd_BUG_ON(!snd_pcm_plug_first(plug))) 97 return -ENXIO; 98 if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) { 99 struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug); 100 while (plugin->next) { 101 if (plugin->dst_frames) 102 frames = plugin->dst_frames(plugin, frames); 103 if ((snd_pcm_sframes_t)frames <= 0) 104 return -ENXIO; 105 plugin = plugin->next; 106 err = snd_pcm_plugin_alloc(plugin, frames); 107 if (err < 0) 108 return err; 109 } 110 } else { 111 struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug); 112 while (plugin->prev) { 113 if (plugin->src_frames) 114 frames = plugin->src_frames(plugin, frames); 115 if ((snd_pcm_sframes_t)frames <= 0) 116 return -ENXIO; 117 plugin = plugin->prev; 118 err = snd_pcm_plugin_alloc(plugin, frames); 119 if (err < 0) 120 return err; 121 } 122 } 123 return 0; 124 } 125 126 127 snd_pcm_sframes_t snd_pcm_plugin_client_channels(struct snd_pcm_plugin *plugin, 128 snd_pcm_uframes_t frames, 129 struct snd_pcm_plugin_channel **channels) 130 { 131 *channels = plugin->buf_channels; 132 return frames; 133 } 134 135 int snd_pcm_plugin_build(struct snd_pcm_substream *plug, 136 const char *name, 137 struct snd_pcm_plugin_format *src_format, 138 struct snd_pcm_plugin_format *dst_format, 139 size_t extra, 140 struct snd_pcm_plugin **ret) 141 { 142 struct snd_pcm_plugin *plugin; 143 unsigned int channels; 144 145 if (snd_BUG_ON(!plug)) 146 return -ENXIO; 147 if (snd_BUG_ON(!src_format || !dst_format)) 148 return -ENXIO; 149 plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL); 150 if (plugin == NULL) 151 return -ENOMEM; 152 plugin->name = name; 153 plugin->plug = plug; 154 plugin->stream = snd_pcm_plug_stream(plug); 155 plugin->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; 156 plugin->src_format = *src_format; 157 plugin->src_width = snd_pcm_format_physical_width(src_format->format); 158 snd_BUG_ON(plugin->src_width <= 0); 159 plugin->dst_format = *dst_format; 160 plugin->dst_width = snd_pcm_format_physical_width(dst_format->format); 161 snd_BUG_ON(plugin->dst_width <= 0); 162 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) 163 channels = src_format->channels; 164 else 165 channels = dst_format->channels; 166 plugin->buf_channels = kzalloc_objs(*plugin->buf_channels, channels); 167 if (plugin->buf_channels == NULL) { 168 snd_pcm_plugin_free(plugin); 169 return -ENOMEM; 170 } 171 plugin->client_channels = snd_pcm_plugin_client_channels; 172 *ret = plugin; 173 return 0; 174 } 175 176 int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin) 177 { 178 if (! plugin) 179 return 0; 180 if (plugin->private_free) 181 plugin->private_free(plugin); 182 kfree(plugin->buf_channels); 183 kvfree(plugin->buf); 184 kfree(plugin); 185 return 0; 186 } 187 188 static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug, 189 snd_pcm_sframes_t frames, 190 bool check_size) 191 { 192 struct snd_pcm_plugin *plugin, *plugin_next; 193 194 plugin = snd_pcm_plug_first(plug); 195 while (plugin && frames > 0) { 196 plugin_next = plugin->next; 197 if (check_size && plugin->buf_frames && 198 frames > plugin->buf_frames) 199 frames = plugin->buf_frames; 200 if (plugin->dst_frames) { 201 frames = plugin->dst_frames(plugin, frames); 202 if (frames < 0) 203 return frames; 204 } 205 plugin = plugin_next; 206 } 207 return frames; 208 } 209 210 static snd_pcm_sframes_t calc_src_frames(struct snd_pcm_substream *plug, 211 snd_pcm_sframes_t frames, 212 bool check_size) 213 { 214 struct snd_pcm_plugin *plugin, *plugin_prev; 215 216 plugin = snd_pcm_plug_last(plug); 217 while (plugin && frames > 0) { 218 plugin_prev = plugin->prev; 219 if (plugin->src_frames) { 220 frames = plugin->src_frames(plugin, frames); 221 if (frames < 0) 222 return frames; 223 } 224 if (check_size && plugin->buf_frames && 225 frames > plugin->buf_frames) 226 frames = plugin->buf_frames; 227 plugin = plugin_prev; 228 } 229 return frames; 230 } 231 232 snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames) 233 { 234 if (snd_BUG_ON(!plug)) 235 return -ENXIO; 236 switch (snd_pcm_plug_stream(plug)) { 237 case SNDRV_PCM_STREAM_PLAYBACK: 238 return calc_src_frames(plug, drv_frames, false); 239 case SNDRV_PCM_STREAM_CAPTURE: 240 return calc_dst_frames(plug, drv_frames, false); 241 default: 242 snd_BUG(); 243 return -EINVAL; 244 } 245 } 246 247 snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t clt_frames) 248 { 249 if (snd_BUG_ON(!plug)) 250 return -ENXIO; 251 switch (snd_pcm_plug_stream(plug)) { 252 case SNDRV_PCM_STREAM_PLAYBACK: 253 return calc_dst_frames(plug, clt_frames, false); 254 case SNDRV_PCM_STREAM_CAPTURE: 255 return calc_src_frames(plug, clt_frames, false); 256 default: 257 snd_BUG(); 258 return -EINVAL; 259 } 260 } 261 262 static int snd_pcm_plug_formats(const struct snd_mask *mask, 263 snd_pcm_format_t format) 264 { 265 struct snd_mask formats = *mask; 266 u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | 267 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | 268 SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | 269 SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE | 270 SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE | 271 SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_S24_3LE | 272 SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE | 273 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE | 274 SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE); 275 snd_mask_set(&formats, (__force int)SNDRV_PCM_FORMAT_MU_LAW); 276 277 if (formats.bits[0] & lower_32_bits(linfmts)) 278 formats.bits[0] |= lower_32_bits(linfmts); 279 if (formats.bits[1] & upper_32_bits(linfmts)) 280 formats.bits[1] |= upper_32_bits(linfmts); 281 return snd_mask_test(&formats, (__force int)format); 282 } 283 284 static const snd_pcm_format_t preferred_formats[] = { 285 SNDRV_PCM_FORMAT_S16_LE, 286 SNDRV_PCM_FORMAT_S16_BE, 287 SNDRV_PCM_FORMAT_U16_LE, 288 SNDRV_PCM_FORMAT_U16_BE, 289 SNDRV_PCM_FORMAT_S24_3LE, 290 SNDRV_PCM_FORMAT_S24_3BE, 291 SNDRV_PCM_FORMAT_U24_3LE, 292 SNDRV_PCM_FORMAT_U24_3BE, 293 SNDRV_PCM_FORMAT_S24_LE, 294 SNDRV_PCM_FORMAT_S24_BE, 295 SNDRV_PCM_FORMAT_U24_LE, 296 SNDRV_PCM_FORMAT_U24_BE, 297 SNDRV_PCM_FORMAT_S32_LE, 298 SNDRV_PCM_FORMAT_S32_BE, 299 SNDRV_PCM_FORMAT_U32_LE, 300 SNDRV_PCM_FORMAT_U32_BE, 301 SNDRV_PCM_FORMAT_S8, 302 SNDRV_PCM_FORMAT_U8 303 }; 304 305 snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, 306 const struct snd_mask *format_mask) 307 { 308 int i; 309 310 if (snd_mask_test(format_mask, (__force int)format)) 311 return format; 312 if (!snd_pcm_plug_formats(format_mask, format)) 313 return (__force snd_pcm_format_t)-EINVAL; 314 if (snd_pcm_format_linear(format)) { 315 unsigned int width = snd_pcm_format_width(format); 316 int unsignd = snd_pcm_format_unsigned(format) > 0; 317 int big = snd_pcm_format_big_endian(format) > 0; 318 unsigned int badness, best = -1; 319 snd_pcm_format_t best_format = (__force snd_pcm_format_t)-1; 320 for (i = 0; i < ARRAY_SIZE(preferred_formats); i++) { 321 snd_pcm_format_t f = preferred_formats[i]; 322 unsigned int w; 323 if (!snd_mask_test(format_mask, (__force int)f)) 324 continue; 325 w = snd_pcm_format_width(f); 326 if (w >= width) 327 badness = w - width; 328 else 329 badness = width - w + 32; 330 badness += snd_pcm_format_unsigned(f) != unsignd; 331 badness += snd_pcm_format_big_endian(f) != big; 332 if (badness < best) { 333 best_format = f; 334 best = badness; 335 } 336 } 337 if ((__force int)best_format >= 0) 338 return best_format; 339 else 340 return (__force snd_pcm_format_t)-EINVAL; 341 } else { 342 switch (format) { 343 case SNDRV_PCM_FORMAT_MU_LAW: 344 for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) { 345 snd_pcm_format_t format1 = preferred_formats[i]; 346 if (snd_mask_test(format_mask, (__force int)format1)) 347 return format1; 348 } 349 fallthrough; 350 default: 351 return (__force snd_pcm_format_t)-EINVAL; 352 } 353 } 354 } 355 356 int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug, 357 struct snd_pcm_hw_params *params, 358 struct snd_pcm_hw_params *slave_params) 359 { 360 struct snd_pcm_plugin_format tmpformat; 361 struct snd_pcm_plugin_format dstformat; 362 struct snd_pcm_plugin_format srcformat; 363 snd_pcm_access_t src_access, dst_access; 364 struct snd_pcm_plugin *plugin = NULL; 365 int err; 366 int stream = snd_pcm_plug_stream(plug); 367 int slave_interleaved = (params_channels(slave_params) == 1 || 368 params_access(slave_params) == SNDRV_PCM_ACCESS_RW_INTERLEAVED); 369 370 switch (stream) { 371 case SNDRV_PCM_STREAM_PLAYBACK: 372 dstformat.format = params_format(slave_params); 373 dstformat.rate = params_rate(slave_params); 374 dstformat.channels = params_channels(slave_params); 375 srcformat.format = params_format(params); 376 srcformat.rate = params_rate(params); 377 srcformat.channels = params_channels(params); 378 src_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; 379 dst_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED : 380 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED); 381 break; 382 case SNDRV_PCM_STREAM_CAPTURE: 383 dstformat.format = params_format(params); 384 dstformat.rate = params_rate(params); 385 dstformat.channels = params_channels(params); 386 srcformat.format = params_format(slave_params); 387 srcformat.rate = params_rate(slave_params); 388 srcformat.channels = params_channels(slave_params); 389 src_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED : 390 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED); 391 dst_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; 392 break; 393 default: 394 snd_BUG(); 395 return -EINVAL; 396 } 397 tmpformat = srcformat; 398 399 pdprintf("srcformat: format=%i, rate=%i, channels=%i\n", 400 srcformat.format, 401 srcformat.rate, 402 srcformat.channels); 403 pdprintf("dstformat: format=%i, rate=%i, channels=%i\n", 404 dstformat.format, 405 dstformat.rate, 406 dstformat.channels); 407 408 /* Format change (linearization) */ 409 if (! rate_match(srcformat.rate, dstformat.rate) && 410 ! snd_pcm_format_linear(srcformat.format)) { 411 if (srcformat.format != SNDRV_PCM_FORMAT_MU_LAW) 412 return -EINVAL; 413 tmpformat.format = SNDRV_PCM_FORMAT_S16; 414 err = snd_pcm_plugin_build_mulaw(plug, 415 &srcformat, &tmpformat, 416 &plugin); 417 if (err < 0) 418 return err; 419 err = snd_pcm_plugin_append(plugin); 420 if (err < 0) { 421 snd_pcm_plugin_free(plugin); 422 return err; 423 } 424 srcformat = tmpformat; 425 src_access = dst_access; 426 } 427 428 /* channels reduction */ 429 if (srcformat.channels > dstformat.channels) { 430 tmpformat.channels = dstformat.channels; 431 err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin); 432 pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err); 433 if (err < 0) 434 return err; 435 err = snd_pcm_plugin_append(plugin); 436 if (err < 0) { 437 snd_pcm_plugin_free(plugin); 438 return err; 439 } 440 srcformat = tmpformat; 441 src_access = dst_access; 442 } 443 444 /* rate resampling */ 445 if (!rate_match(srcformat.rate, dstformat.rate)) { 446 if (srcformat.format != SNDRV_PCM_FORMAT_S16) { 447 /* convert to S16 for resampling */ 448 tmpformat.format = SNDRV_PCM_FORMAT_S16; 449 err = snd_pcm_plugin_build_linear(plug, 450 &srcformat, &tmpformat, 451 &plugin); 452 if (err < 0) 453 return err; 454 err = snd_pcm_plugin_append(plugin); 455 if (err < 0) { 456 snd_pcm_plugin_free(plugin); 457 return err; 458 } 459 srcformat = tmpformat; 460 src_access = dst_access; 461 } 462 tmpformat.rate = dstformat.rate; 463 err = snd_pcm_plugin_build_rate(plug, 464 &srcformat, &tmpformat, 465 &plugin); 466 pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err); 467 if (err < 0) 468 return err; 469 err = snd_pcm_plugin_append(plugin); 470 if (err < 0) { 471 snd_pcm_plugin_free(plugin); 472 return err; 473 } 474 srcformat = tmpformat; 475 src_access = dst_access; 476 } 477 478 /* format change */ 479 if (srcformat.format != dstformat.format) { 480 tmpformat.format = dstformat.format; 481 if (srcformat.format == SNDRV_PCM_FORMAT_MU_LAW || 482 tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) { 483 err = snd_pcm_plugin_build_mulaw(plug, 484 &srcformat, &tmpformat, 485 &plugin); 486 } 487 else if (snd_pcm_format_linear(srcformat.format) && 488 snd_pcm_format_linear(tmpformat.format)) { 489 err = snd_pcm_plugin_build_linear(plug, 490 &srcformat, &tmpformat, 491 &plugin); 492 } 493 else 494 return -EINVAL; 495 pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err); 496 if (err < 0) 497 return err; 498 err = snd_pcm_plugin_append(plugin); 499 if (err < 0) { 500 snd_pcm_plugin_free(plugin); 501 return err; 502 } 503 srcformat = tmpformat; 504 src_access = dst_access; 505 } 506 507 /* channels extension */ 508 if (srcformat.channels < dstformat.channels) { 509 tmpformat.channels = dstformat.channels; 510 err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin); 511 pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err); 512 if (err < 0) 513 return err; 514 err = snd_pcm_plugin_append(plugin); 515 if (err < 0) { 516 snd_pcm_plugin_free(plugin); 517 return err; 518 } 519 srcformat = tmpformat; 520 src_access = dst_access; 521 } 522 523 /* de-interleave */ 524 if (src_access != dst_access) { 525 err = snd_pcm_plugin_build_copy(plug, 526 &srcformat, 527 &tmpformat, 528 &plugin); 529 pdprintf("interleave change (copy: returns %i)\n", err); 530 if (err < 0) 531 return err; 532 err = snd_pcm_plugin_append(plugin); 533 if (err < 0) { 534 snd_pcm_plugin_free(plugin); 535 return err; 536 } 537 } 538 539 return 0; 540 } 541 542 snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plug, 543 char *buf, 544 snd_pcm_uframes_t count, 545 struct snd_pcm_plugin_channel **channels) 546 { 547 struct snd_pcm_plugin *plugin; 548 struct snd_pcm_plugin_channel *v; 549 struct snd_pcm_plugin_format *format; 550 int width, nchannels, channel; 551 int stream = snd_pcm_plug_stream(plug); 552 553 if (snd_BUG_ON(!buf)) 554 return -ENXIO; 555 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 556 plugin = snd_pcm_plug_first(plug); 557 format = &plugin->src_format; 558 } else { 559 plugin = snd_pcm_plug_last(plug); 560 format = &plugin->dst_format; 561 } 562 v = plugin->buf_channels; 563 *channels = v; 564 width = snd_pcm_format_physical_width(format->format); 565 if (width < 0) 566 return width; 567 nchannels = format->channels; 568 if (snd_BUG_ON(plugin->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && 569 format->channels > 1)) 570 return -ENXIO; 571 for (channel = 0; channel < nchannels; channel++, v++) { 572 v->frames = count; 573 v->enabled = 1; 574 v->wanted = (stream == SNDRV_PCM_STREAM_CAPTURE); 575 v->area.addr = buf; 576 v->area.first = channel * width; 577 v->area.step = nchannels * width; 578 } 579 return count; 580 } 581 582 snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *src_channels, snd_pcm_uframes_t size) 583 { 584 struct snd_pcm_plugin *plugin, *next; 585 struct snd_pcm_plugin_channel *dst_channels; 586 int err; 587 snd_pcm_sframes_t frames = size; 588 589 plugin = snd_pcm_plug_first(plug); 590 while (plugin) { 591 if (frames <= 0) 592 return frames; 593 next = plugin->next; 594 if (next) { 595 snd_pcm_sframes_t frames1 = frames; 596 if (plugin->dst_frames) { 597 frames1 = plugin->dst_frames(plugin, frames); 598 if (frames1 <= 0) 599 return frames1; 600 } 601 err = next->client_channels(next, frames1, &dst_channels); 602 if (err < 0) 603 return err; 604 if (err != frames1) { 605 frames = err; 606 if (plugin->src_frames) { 607 frames = plugin->src_frames(plugin, frames1); 608 if (frames <= 0) 609 return frames; 610 } 611 } 612 } else 613 dst_channels = NULL; 614 pdprintf("write plugin: %s, %li\n", plugin->name, frames); 615 frames = plugin->transfer(plugin, src_channels, dst_channels, frames); 616 if (frames < 0) 617 return frames; 618 src_channels = dst_channels; 619 plugin = next; 620 } 621 return calc_src_frames(plug, frames, true); 622 } 623 624 snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *dst_channels_final, snd_pcm_uframes_t size) 625 { 626 struct snd_pcm_plugin *plugin, *next; 627 struct snd_pcm_plugin_channel *src_channels, *dst_channels; 628 snd_pcm_sframes_t frames = size; 629 int err; 630 631 frames = calc_src_frames(plug, frames, true); 632 if (frames < 0) 633 return frames; 634 635 src_channels = NULL; 636 plugin = snd_pcm_plug_first(plug); 637 while (plugin && frames > 0) { 638 next = plugin->next; 639 if (next) { 640 err = plugin->client_channels(plugin, frames, &dst_channels); 641 if (err < 0) 642 return err; 643 frames = err; 644 } else { 645 dst_channels = dst_channels_final; 646 } 647 pdprintf("read plugin: %s, %li\n", plugin->name, frames); 648 frames = plugin->transfer(plugin, src_channels, dst_channels, frames); 649 if (frames < 0) 650 return frames; 651 plugin = next; 652 src_channels = dst_channels; 653 } 654 return frames; 655 } 656 657 int snd_pcm_area_silence(const struct snd_pcm_channel_area *dst_area, size_t dst_offset, 658 size_t samples, snd_pcm_format_t format) 659 { 660 /* FIXME: sub byte resolution and odd dst_offset */ 661 unsigned char *dst; 662 unsigned int dst_step; 663 int width; 664 const unsigned char *silence; 665 if (!dst_area->addr) 666 return 0; 667 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; 668 width = snd_pcm_format_physical_width(format); 669 if (width <= 0) 670 return -EINVAL; 671 if (dst_area->step == (unsigned int) width && width >= 8) 672 return snd_pcm_format_set_silence(format, dst, samples); 673 silence = snd_pcm_format_silence_64(format); 674 if (! silence) 675 return -EINVAL; 676 dst_step = dst_area->step / 8; 677 if (width == 4) { 678 /* Ima ADPCM */ 679 int dstbit = dst_area->first % 8; 680 int dstbit_step = dst_area->step % 8; 681 while (samples-- > 0) { 682 if (dstbit) 683 *dst &= 0xf0; 684 else 685 *dst &= 0x0f; 686 dst += dst_step; 687 dstbit += dstbit_step; 688 if (dstbit == 8) { 689 dst++; 690 dstbit = 0; 691 } 692 } 693 } else { 694 width /= 8; 695 while (samples-- > 0) { 696 memcpy(dst, silence, width); 697 dst += dst_step; 698 } 699 } 700 return 0; 701 } 702 703 int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_area, size_t src_offset, 704 const struct snd_pcm_channel_area *dst_area, size_t dst_offset, 705 size_t samples, snd_pcm_format_t format) 706 { 707 /* FIXME: sub byte resolution and odd dst_offset */ 708 char *src, *dst; 709 int width; 710 int src_step, dst_step; 711 src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8; 712 if (!src_area->addr) 713 return snd_pcm_area_silence(dst_area, dst_offset, samples, format); 714 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; 715 if (!dst_area->addr) 716 return 0; 717 width = snd_pcm_format_physical_width(format); 718 if (width <= 0) 719 return -EINVAL; 720 if (src_area->step == (unsigned int) width && 721 dst_area->step == (unsigned int) width && width >= 8) { 722 size_t bytes = samples * width / 8; 723 memcpy(dst, src, bytes); 724 return 0; 725 } 726 src_step = src_area->step / 8; 727 dst_step = dst_area->step / 8; 728 if (width == 4) { 729 /* Ima ADPCM */ 730 int srcbit = src_area->first % 8; 731 int srcbit_step = src_area->step % 8; 732 int dstbit = dst_area->first % 8; 733 int dstbit_step = dst_area->step % 8; 734 while (samples-- > 0) { 735 unsigned char srcval; 736 if (srcbit) 737 srcval = *src & 0x0f; 738 else 739 srcval = (*src & 0xf0) >> 4; 740 if (dstbit) 741 *dst = (*dst & 0xf0) | srcval; 742 else 743 *dst = (*dst & 0x0f) | (srcval << 4); 744 src += src_step; 745 srcbit += srcbit_step; 746 if (srcbit == 8) { 747 src++; 748 srcbit = 0; 749 } 750 dst += dst_step; 751 dstbit += dstbit_step; 752 if (dstbit == 8) { 753 dst++; 754 dstbit = 0; 755 } 756 } 757 } else { 758 width /= 8; 759 while (samples-- > 0) { 760 memcpy(dst, src, width); 761 src += src_step; 762 dst += dst_step; 763 } 764 } 765 return 0; 766 } 767