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