1 /* 2 * PCM Plug-In shared (kernel/library) code 3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.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 <sound/driver.h> 28 #include <linux/slab.h> 29 #include <linux/time.h> 30 #include <linux/vmalloc.h> 31 #include <sound/core.h> 32 #include <sound/pcm.h> 33 #include <sound/pcm_params.h> 34 #include "pcm_plugin.h" 35 36 #define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first) 37 #define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last) 38 39 static int snd_pcm_plugin_src_channels_mask(snd_pcm_plugin_t *plugin, 40 bitset_t *dst_vmask, 41 bitset_t **src_vmask) 42 { 43 bitset_t *vmask = plugin->src_vmask; 44 bitset_copy(vmask, dst_vmask, plugin->src_format.channels); 45 *src_vmask = vmask; 46 return 0; 47 } 48 49 static int snd_pcm_plugin_dst_channels_mask(snd_pcm_plugin_t *plugin, 50 bitset_t *src_vmask, 51 bitset_t **dst_vmask) 52 { 53 bitset_t *vmask = plugin->dst_vmask; 54 bitset_copy(vmask, src_vmask, plugin->dst_format.channels); 55 *dst_vmask = vmask; 56 return 0; 57 } 58 59 /* 60 * because some cards might have rates "very close", we ignore 61 * all "resampling" requests within +-5% 62 */ 63 static int rate_match(unsigned int src_rate, unsigned int dst_rate) 64 { 65 unsigned int low = (src_rate * 95) / 100; 66 unsigned int high = (src_rate * 105) / 100; 67 return dst_rate >= low && dst_rate <= high; 68 } 69 70 static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t frames) 71 { 72 snd_pcm_plugin_format_t *format; 73 ssize_t width; 74 size_t size; 75 unsigned int channel; 76 snd_pcm_plugin_channel_t *c; 77 78 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) { 79 format = &plugin->src_format; 80 } else { 81 format = &plugin->dst_format; 82 } 83 if ((width = snd_pcm_format_physical_width(format->format)) < 0) 84 return width; 85 size = frames * format->channels * width; 86 snd_assert((size % 8) == 0, return -ENXIO); 87 size /= 8; 88 if (plugin->buf_frames < frames) { 89 vfree(plugin->buf); 90 plugin->buf = vmalloc(size); 91 plugin->buf_frames = frames; 92 } 93 if (!plugin->buf) { 94 plugin->buf_frames = 0; 95 return -ENOMEM; 96 } 97 c = plugin->buf_channels; 98 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { 99 for (channel = 0; channel < format->channels; channel++, c++) { 100 c->frames = frames; 101 c->enabled = 1; 102 c->wanted = 0; 103 c->area.addr = plugin->buf; 104 c->area.first = channel * width; 105 c->area.step = format->channels * width; 106 } 107 } else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { 108 snd_assert((size % format->channels) == 0,); 109 size /= format->channels; 110 for (channel = 0; channel < format->channels; channel++, c++) { 111 c->frames = frames; 112 c->enabled = 1; 113 c->wanted = 0; 114 c->area.addr = plugin->buf + (channel * size); 115 c->area.first = 0; 116 c->area.step = width; 117 } 118 } else 119 return -EINVAL; 120 return 0; 121 } 122 123 int snd_pcm_plug_alloc(snd_pcm_plug_t *plug, snd_pcm_uframes_t frames) 124 { 125 int err; 126 snd_assert(snd_pcm_plug_first(plug) != NULL, return -ENXIO); 127 if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) { 128 snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug); 129 while (plugin->next) { 130 if (plugin->dst_frames) 131 frames = plugin->dst_frames(plugin, frames); 132 snd_assert(frames > 0, return -ENXIO); 133 plugin = plugin->next; 134 err = snd_pcm_plugin_alloc(plugin, frames); 135 if (err < 0) 136 return err; 137 } 138 } else { 139 snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug); 140 while (plugin->prev) { 141 if (plugin->src_frames) 142 frames = plugin->src_frames(plugin, frames); 143 snd_assert(frames > 0, return -ENXIO); 144 plugin = plugin->prev; 145 err = snd_pcm_plugin_alloc(plugin, frames); 146 if (err < 0) 147 return err; 148 } 149 } 150 return 0; 151 } 152 153 154 snd_pcm_sframes_t snd_pcm_plugin_client_channels(snd_pcm_plugin_t *plugin, 155 snd_pcm_uframes_t frames, 156 snd_pcm_plugin_channel_t **channels) 157 { 158 *channels = plugin->buf_channels; 159 return frames; 160 } 161 162 int snd_pcm_plugin_build(snd_pcm_plug_t *plug, 163 const char *name, 164 snd_pcm_plugin_format_t *src_format, 165 snd_pcm_plugin_format_t *dst_format, 166 size_t extra, 167 snd_pcm_plugin_t **ret) 168 { 169 snd_pcm_plugin_t *plugin; 170 unsigned int channels; 171 172 snd_assert(plug != NULL, return -ENXIO); 173 snd_assert(src_format != NULL && dst_format != NULL, return -ENXIO); 174 plugin = kcalloc(1, sizeof(*plugin) + extra, GFP_KERNEL); 175 if (plugin == NULL) 176 return -ENOMEM; 177 plugin->name = name; 178 plugin->plug = plug; 179 plugin->stream = snd_pcm_plug_stream(plug); 180 plugin->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; 181 plugin->src_format = *src_format; 182 plugin->src_width = snd_pcm_format_physical_width(src_format->format); 183 snd_assert(plugin->src_width > 0, ); 184 plugin->dst_format = *dst_format; 185 plugin->dst_width = snd_pcm_format_physical_width(dst_format->format); 186 snd_assert(plugin->dst_width > 0, ); 187 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) 188 channels = src_format->channels; 189 else 190 channels = dst_format->channels; 191 plugin->buf_channels = kcalloc(channels, sizeof(*plugin->buf_channels), GFP_KERNEL); 192 if (plugin->buf_channels == NULL) { 193 snd_pcm_plugin_free(plugin); 194 return -ENOMEM; 195 } 196 plugin->src_vmask = bitset_alloc(src_format->channels); 197 if (plugin->src_vmask == NULL) { 198 snd_pcm_plugin_free(plugin); 199 return -ENOMEM; 200 } 201 plugin->dst_vmask = bitset_alloc(dst_format->channels); 202 if (plugin->dst_vmask == NULL) { 203 snd_pcm_plugin_free(plugin); 204 return -ENOMEM; 205 } 206 plugin->client_channels = snd_pcm_plugin_client_channels; 207 plugin->src_channels_mask = snd_pcm_plugin_src_channels_mask; 208 plugin->dst_channels_mask = snd_pcm_plugin_dst_channels_mask; 209 *ret = plugin; 210 return 0; 211 } 212 213 int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin) 214 { 215 if (! plugin) 216 return 0; 217 if (plugin->private_free) 218 plugin->private_free(plugin); 219 kfree(plugin->buf_channels); 220 vfree(plugin->buf); 221 kfree(plugin->src_vmask); 222 kfree(plugin->dst_vmask); 223 kfree(plugin); 224 return 0; 225 } 226 227 snd_pcm_sframes_t snd_pcm_plug_client_size(snd_pcm_plug_t *plug, snd_pcm_uframes_t drv_frames) 228 { 229 snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next; 230 int stream = snd_pcm_plug_stream(plug); 231 232 snd_assert(plug != NULL, return -ENXIO); 233 if (drv_frames == 0) 234 return 0; 235 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 236 plugin = snd_pcm_plug_last(plug); 237 while (plugin && drv_frames > 0) { 238 plugin_prev = plugin->prev; 239 if (plugin->src_frames) 240 drv_frames = plugin->src_frames(plugin, drv_frames); 241 plugin = plugin_prev; 242 } 243 } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { 244 plugin = snd_pcm_plug_first(plug); 245 while (plugin && drv_frames > 0) { 246 plugin_next = plugin->next; 247 if (plugin->dst_frames) 248 drv_frames = plugin->dst_frames(plugin, drv_frames); 249 plugin = plugin_next; 250 } 251 } else 252 snd_BUG(); 253 return drv_frames; 254 } 255 256 snd_pcm_sframes_t snd_pcm_plug_slave_size(snd_pcm_plug_t *plug, snd_pcm_uframes_t clt_frames) 257 { 258 snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next; 259 snd_pcm_sframes_t frames; 260 int stream = snd_pcm_plug_stream(plug); 261 262 snd_assert(plug != NULL, return -ENXIO); 263 if (clt_frames == 0) 264 return 0; 265 frames = clt_frames; 266 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 267 plugin = snd_pcm_plug_first(plug); 268 while (plugin && frames > 0) { 269 plugin_next = plugin->next; 270 if (plugin->dst_frames) { 271 frames = plugin->dst_frames(plugin, frames); 272 if (frames < 0) 273 return frames; 274 } 275 plugin = plugin_next; 276 } 277 } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { 278 plugin = snd_pcm_plug_last(plug); 279 while (plugin) { 280 plugin_prev = plugin->prev; 281 if (plugin->src_frames) { 282 frames = plugin->src_frames(plugin, frames); 283 if (frames < 0) 284 return frames; 285 } 286 plugin = plugin_prev; 287 } 288 } else 289 snd_BUG(); 290 return frames; 291 } 292 293 static int snd_pcm_plug_formats(snd_mask_t *mask, int format) 294 { 295 snd_mask_t formats = *mask; 296 u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | 297 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | 298 SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | 299 SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE | 300 SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE | 301 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE | 302 SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE); 303 snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW); 304 305 if (formats.bits[0] & (u32)linfmts) 306 formats.bits[0] |= (u32)linfmts; 307 if (formats.bits[1] & (u32)(linfmts >> 32)) 308 formats.bits[1] |= (u32)(linfmts >> 32); 309 return snd_mask_test(&formats, format); 310 } 311 312 static int preferred_formats[] = { 313 SNDRV_PCM_FORMAT_S16_LE, 314 SNDRV_PCM_FORMAT_S16_BE, 315 SNDRV_PCM_FORMAT_U16_LE, 316 SNDRV_PCM_FORMAT_U16_BE, 317 SNDRV_PCM_FORMAT_S24_LE, 318 SNDRV_PCM_FORMAT_S24_BE, 319 SNDRV_PCM_FORMAT_U24_LE, 320 SNDRV_PCM_FORMAT_U24_BE, 321 SNDRV_PCM_FORMAT_S32_LE, 322 SNDRV_PCM_FORMAT_S32_BE, 323 SNDRV_PCM_FORMAT_U32_LE, 324 SNDRV_PCM_FORMAT_U32_BE, 325 SNDRV_PCM_FORMAT_S8, 326 SNDRV_PCM_FORMAT_U8 327 }; 328 329 int snd_pcm_plug_slave_format(int format, snd_mask_t *format_mask) 330 { 331 if (snd_mask_test(format_mask, format)) 332 return format; 333 if (! snd_pcm_plug_formats(format_mask, format)) 334 return -EINVAL; 335 if (snd_pcm_format_linear(format)) { 336 int width = snd_pcm_format_width(format); 337 int unsignd = snd_pcm_format_unsigned(format); 338 int big = snd_pcm_format_big_endian(format); 339 int format1; 340 int wid, width1=width; 341 int dwidth1 = 8; 342 for (wid = 0; wid < 4; ++wid) { 343 int end, big1 = big; 344 for (end = 0; end < 2; ++end) { 345 int sgn, unsignd1 = unsignd; 346 for (sgn = 0; sgn < 2; ++sgn) { 347 format1 = snd_pcm_build_linear_format(width1, unsignd1, big1); 348 if (format1 >= 0 && 349 snd_mask_test(format_mask, format1)) 350 goto _found; 351 unsignd1 = !unsignd1; 352 } 353 big1 = !big1; 354 } 355 if (width1 == 32) { 356 dwidth1 = -dwidth1; 357 width1 = width; 358 } 359 width1 += dwidth1; 360 } 361 return -EINVAL; 362 _found: 363 return format1; 364 } else { 365 unsigned int i; 366 switch (format) { 367 case SNDRV_PCM_FORMAT_MU_LAW: 368 for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) { 369 int format1 = preferred_formats[i]; 370 if (snd_mask_test(format_mask, format1)) 371 return format1; 372 } 373 default: 374 return -EINVAL; 375 } 376 } 377 } 378 379 int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug, 380 snd_pcm_hw_params_t *params, 381 snd_pcm_hw_params_t *slave_params) 382 { 383 snd_pcm_plugin_format_t tmpformat; 384 snd_pcm_plugin_format_t dstformat; 385 snd_pcm_plugin_format_t srcformat; 386 int src_access, dst_access; 387 snd_pcm_plugin_t *plugin = NULL; 388 int err; 389 int stream = snd_pcm_plug_stream(plug); 390 int slave_interleaved = (params_channels(slave_params) == 1 || 391 params_access(slave_params) == SNDRV_PCM_ACCESS_RW_INTERLEAVED); 392 393 switch (stream) { 394 case SNDRV_PCM_STREAM_PLAYBACK: 395 dstformat.format = params_format(slave_params); 396 dstformat.rate = params_rate(slave_params); 397 dstformat.channels = params_channels(slave_params); 398 srcformat.format = params_format(params); 399 srcformat.rate = params_rate(params); 400 srcformat.channels = params_channels(params); 401 src_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; 402 dst_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED : 403 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED); 404 break; 405 case SNDRV_PCM_STREAM_CAPTURE: 406 dstformat.format = params_format(params); 407 dstformat.rate = params_rate(params); 408 dstformat.channels = params_channels(params); 409 srcformat.format = params_format(slave_params); 410 srcformat.rate = params_rate(slave_params); 411 srcformat.channels = params_channels(slave_params); 412 src_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED : 413 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED); 414 dst_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; 415 break; 416 default: 417 snd_BUG(); 418 return -EINVAL; 419 } 420 tmpformat = srcformat; 421 422 pdprintf("srcformat: format=%i, rate=%i, channels=%i\n", 423 srcformat.format, 424 srcformat.rate, 425 srcformat.channels); 426 pdprintf("dstformat: format=%i, rate=%i, channels=%i\n", 427 dstformat.format, 428 dstformat.rate, 429 dstformat.channels); 430 431 /* Format change (linearization) */ 432 if ((srcformat.format != dstformat.format || 433 !rate_match(srcformat.rate, dstformat.rate) || 434 srcformat.channels != dstformat.channels) && 435 !snd_pcm_format_linear(srcformat.format)) { 436 if (snd_pcm_format_linear(dstformat.format)) 437 tmpformat.format = dstformat.format; 438 else 439 tmpformat.format = SNDRV_PCM_FORMAT_S16; 440 switch (srcformat.format) { 441 case SNDRV_PCM_FORMAT_MU_LAW: 442 err = snd_pcm_plugin_build_mulaw(plug, 443 &srcformat, &tmpformat, 444 &plugin); 445 break; 446 default: 447 return -EINVAL; 448 } 449 pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err); 450 if (err < 0) 451 return err; 452 err = snd_pcm_plugin_append(plugin); 453 if (err < 0) { 454 snd_pcm_plugin_free(plugin); 455 return err; 456 } 457 srcformat = tmpformat; 458 src_access = dst_access; 459 } 460 461 /* channels reduction */ 462 if (srcformat.channels > dstformat.channels) { 463 int sv = srcformat.channels; 464 int dv = dstformat.channels; 465 route_ttable_entry_t *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL); 466 if (ttable == NULL) 467 return -ENOMEM; 468 #if 1 469 if (sv == 2 && dv == 1) { 470 ttable[0] = HALF; 471 ttable[1] = HALF; 472 } else 473 #endif 474 { 475 int v; 476 for (v = 0; v < dv; ++v) 477 ttable[v * sv + v] = FULL; 478 } 479 tmpformat.channels = dstformat.channels; 480 if (rate_match(srcformat.rate, dstformat.rate) && 481 snd_pcm_format_linear(dstformat.format)) 482 tmpformat.format = dstformat.format; 483 err = snd_pcm_plugin_build_route(plug, 484 &srcformat, &tmpformat, 485 ttable, &plugin); 486 kfree(ttable); 487 pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err); 488 if (err < 0) { 489 snd_pcm_plugin_free(plugin); 490 return err; 491 } 492 err = snd_pcm_plugin_append(plugin); 493 if (err < 0) { 494 snd_pcm_plugin_free(plugin); 495 return err; 496 } 497 srcformat = tmpformat; 498 src_access = dst_access; 499 } 500 501 /* rate resampling */ 502 if (!rate_match(srcformat.rate, dstformat.rate)) { 503 tmpformat.rate = dstformat.rate; 504 if (srcformat.channels == dstformat.channels && 505 snd_pcm_format_linear(dstformat.format)) 506 tmpformat.format = dstformat.format; 507 err = snd_pcm_plugin_build_rate(plug, 508 &srcformat, &tmpformat, 509 &plugin); 510 pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err); 511 if (err < 0) { 512 snd_pcm_plugin_free(plugin); 513 return err; 514 } 515 err = snd_pcm_plugin_append(plugin); 516 if (err < 0) { 517 snd_pcm_plugin_free(plugin); 518 return err; 519 } 520 srcformat = tmpformat; 521 src_access = dst_access; 522 } 523 524 /* channels extension */ 525 if (srcformat.channels < dstformat.channels) { 526 int sv = srcformat.channels; 527 int dv = dstformat.channels; 528 route_ttable_entry_t *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL); 529 if (ttable == NULL) 530 return -ENOMEM; 531 #if 0 532 { 533 int v; 534 for (v = 0; v < sv; ++v) 535 ttable[v * sv + v] = FULL; 536 } 537 #else 538 { 539 /* Playback is spreaded on all channels */ 540 int vd, vs; 541 for (vd = 0, vs = 0; vd < dv; ++vd) { 542 ttable[vd * sv + vs] = FULL; 543 vs++; 544 if (vs == sv) 545 vs = 0; 546 } 547 } 548 #endif 549 tmpformat.channels = dstformat.channels; 550 if (snd_pcm_format_linear(dstformat.format)) 551 tmpformat.format = dstformat.format; 552 err = snd_pcm_plugin_build_route(plug, 553 &srcformat, &tmpformat, 554 ttable, &plugin); 555 kfree(ttable); 556 pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err); 557 if (err < 0) { 558 snd_pcm_plugin_free(plugin); 559 return err; 560 } 561 err = snd_pcm_plugin_append(plugin); 562 if (err < 0) { 563 snd_pcm_plugin_free(plugin); 564 return err; 565 } 566 srcformat = tmpformat; 567 src_access = dst_access; 568 } 569 570 /* format change */ 571 if (srcformat.format != dstformat.format) { 572 tmpformat.format = dstformat.format; 573 if (tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) { 574 err = snd_pcm_plugin_build_mulaw(plug, 575 &srcformat, &tmpformat, 576 &plugin); 577 } 578 else if (snd_pcm_format_linear(srcformat.format) && 579 snd_pcm_format_linear(tmpformat.format)) { 580 err = snd_pcm_plugin_build_linear(plug, 581 &srcformat, &tmpformat, 582 &plugin); 583 } 584 else 585 return -EINVAL; 586 pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err); 587 if (err < 0) 588 return err; 589 err = snd_pcm_plugin_append(plugin); 590 if (err < 0) { 591 snd_pcm_plugin_free(plugin); 592 return err; 593 } 594 srcformat = tmpformat; 595 src_access = dst_access; 596 } 597 598 /* de-interleave */ 599 if (src_access != dst_access) { 600 err = snd_pcm_plugin_build_copy(plug, 601 &srcformat, 602 &tmpformat, 603 &plugin); 604 pdprintf("interleave change (copy: returns %i)\n", err); 605 if (err < 0) 606 return err; 607 err = snd_pcm_plugin_append(plugin); 608 if (err < 0) { 609 snd_pcm_plugin_free(plugin); 610 return err; 611 } 612 } 613 614 return 0; 615 } 616 617 snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(snd_pcm_plug_t *plug, 618 char *buf, 619 snd_pcm_uframes_t count, 620 snd_pcm_plugin_channel_t **channels) 621 { 622 snd_pcm_plugin_t *plugin; 623 snd_pcm_plugin_channel_t *v; 624 snd_pcm_plugin_format_t *format; 625 int width, nchannels, channel; 626 int stream = snd_pcm_plug_stream(plug); 627 628 snd_assert(buf != NULL, return -ENXIO); 629 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 630 plugin = snd_pcm_plug_first(plug); 631 format = &plugin->src_format; 632 } else { 633 plugin = snd_pcm_plug_last(plug); 634 format = &plugin->dst_format; 635 } 636 v = plugin->buf_channels; 637 *channels = v; 638 if ((width = snd_pcm_format_physical_width(format->format)) < 0) 639 return width; 640 nchannels = format->channels; 641 snd_assert(plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || format->channels <= 1, return -ENXIO); 642 for (channel = 0; channel < nchannels; channel++, v++) { 643 v->frames = count; 644 v->enabled = 1; 645 v->wanted = (stream == SNDRV_PCM_STREAM_CAPTURE); 646 v->area.addr = buf; 647 v->area.first = channel * width; 648 v->area.step = nchannels * width; 649 } 650 return count; 651 } 652 653 static int snd_pcm_plug_playback_channels_mask(snd_pcm_plug_t *plug, 654 bitset_t *client_vmask) 655 { 656 snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug); 657 if (plugin == NULL) { 658 return 0; 659 } else { 660 int schannels = plugin->dst_format.channels; 661 bitset_t bs[bitset_size(schannels)]; 662 bitset_t *srcmask; 663 bitset_t *dstmask = bs; 664 int err; 665 bitset_one(dstmask, schannels); 666 if (plugin == NULL) { 667 bitset_and(client_vmask, dstmask, schannels); 668 return 0; 669 } 670 while (1) { 671 err = plugin->src_channels_mask(plugin, dstmask, &srcmask); 672 if (err < 0) 673 return err; 674 dstmask = srcmask; 675 if (plugin->prev == NULL) 676 break; 677 plugin = plugin->prev; 678 } 679 bitset_and(client_vmask, dstmask, plugin->src_format.channels); 680 return 0; 681 } 682 } 683 684 static int snd_pcm_plug_playback_disable_useless_channels(snd_pcm_plug_t *plug, 685 snd_pcm_plugin_channel_t *src_channels) 686 { 687 snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug); 688 unsigned int nchannels = plugin->src_format.channels; 689 bitset_t bs[bitset_size(nchannels)]; 690 bitset_t *srcmask = bs; 691 int err; 692 unsigned int channel; 693 for (channel = 0; channel < nchannels; channel++) { 694 if (src_channels[channel].enabled) 695 bitset_set(srcmask, channel); 696 else 697 bitset_reset(srcmask, channel); 698 } 699 err = snd_pcm_plug_playback_channels_mask(plug, srcmask); 700 if (err < 0) 701 return err; 702 for (channel = 0; channel < nchannels; channel++) { 703 if (!bitset_get(srcmask, channel)) 704 src_channels[channel].enabled = 0; 705 } 706 return 0; 707 } 708 709 static int snd_pcm_plug_capture_disable_useless_channels(snd_pcm_plug_t *plug, 710 snd_pcm_plugin_channel_t *src_channels, 711 snd_pcm_plugin_channel_t *client_channels) 712 { 713 snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug); 714 unsigned int nchannels = plugin->dst_format.channels; 715 bitset_t bs[bitset_size(nchannels)]; 716 bitset_t *dstmask = bs; 717 bitset_t *srcmask; 718 int err; 719 unsigned int channel; 720 for (channel = 0; channel < nchannels; channel++) { 721 if (client_channels[channel].enabled) 722 bitset_set(dstmask, channel); 723 else 724 bitset_reset(dstmask, channel); 725 } 726 while (plugin) { 727 err = plugin->src_channels_mask(plugin, dstmask, &srcmask); 728 if (err < 0) 729 return err; 730 dstmask = srcmask; 731 plugin = plugin->prev; 732 } 733 plugin = snd_pcm_plug_first(plug); 734 nchannels = plugin->src_format.channels; 735 for (channel = 0; channel < nchannels; channel++) { 736 if (!bitset_get(dstmask, channel)) 737 src_channels[channel].enabled = 0; 738 } 739 return 0; 740 } 741 742 snd_pcm_sframes_t snd_pcm_plug_write_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *src_channels, snd_pcm_uframes_t size) 743 { 744 snd_pcm_plugin_t *plugin, *next; 745 snd_pcm_plugin_channel_t *dst_channels; 746 int err; 747 snd_pcm_sframes_t frames = size; 748 749 if ((err = snd_pcm_plug_playback_disable_useless_channels(plug, src_channels)) < 0) 750 return err; 751 752 plugin = snd_pcm_plug_first(plug); 753 while (plugin && frames > 0) { 754 if ((next = plugin->next) != NULL) { 755 snd_pcm_sframes_t frames1 = frames; 756 if (plugin->dst_frames) 757 frames1 = plugin->dst_frames(plugin, frames); 758 if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) { 759 return err; 760 } 761 if (err != frames1) { 762 frames = err; 763 if (plugin->src_frames) 764 frames = plugin->src_frames(plugin, frames1); 765 } 766 } else 767 dst_channels = NULL; 768 pdprintf("write plugin: %s, %li\n", plugin->name, frames); 769 if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) 770 return frames; 771 src_channels = dst_channels; 772 plugin = next; 773 } 774 return snd_pcm_plug_client_size(plug, frames); 775 } 776 777 snd_pcm_sframes_t snd_pcm_plug_read_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *dst_channels_final, snd_pcm_uframes_t size) 778 { 779 snd_pcm_plugin_t *plugin, *next; 780 snd_pcm_plugin_channel_t *src_channels, *dst_channels; 781 snd_pcm_sframes_t frames = size; 782 int err; 783 784 frames = snd_pcm_plug_slave_size(plug, frames); 785 if (frames < 0) 786 return frames; 787 788 src_channels = NULL; 789 plugin = snd_pcm_plug_first(plug); 790 while (plugin && frames > 0) { 791 if ((next = plugin->next) != NULL) { 792 if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) { 793 return err; 794 } 795 frames = err; 796 if (!plugin->prev) { 797 if ((err = snd_pcm_plug_capture_disable_useless_channels(plug, dst_channels, dst_channels_final)) < 0) 798 return err; 799 } 800 } else { 801 dst_channels = dst_channels_final; 802 } 803 pdprintf("read plugin: %s, %li\n", plugin->name, frames); 804 if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) 805 return frames; 806 plugin = next; 807 src_channels = dst_channels; 808 } 809 return frames; 810 } 811 812 int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, size_t dst_offset, 813 size_t samples, int format) 814 { 815 /* FIXME: sub byte resolution and odd dst_offset */ 816 unsigned char *dst; 817 unsigned int dst_step; 818 int width; 819 const unsigned char *silence; 820 if (!dst_area->addr) 821 return 0; 822 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; 823 width = snd_pcm_format_physical_width(format); 824 if (width <= 0) 825 return -EINVAL; 826 if (dst_area->step == (unsigned int) width && width >= 8) 827 return snd_pcm_format_set_silence(format, dst, samples); 828 silence = snd_pcm_format_silence_64(format); 829 if (! silence) 830 return -EINVAL; 831 dst_step = dst_area->step / 8; 832 if (width == 4) { 833 /* Ima ADPCM */ 834 int dstbit = dst_area->first % 8; 835 int dstbit_step = dst_area->step % 8; 836 while (samples-- > 0) { 837 if (dstbit) 838 *dst &= 0xf0; 839 else 840 *dst &= 0x0f; 841 dst += dst_step; 842 dstbit += dstbit_step; 843 if (dstbit == 8) { 844 dst++; 845 dstbit = 0; 846 } 847 } 848 } else { 849 width /= 8; 850 while (samples-- > 0) { 851 memcpy(dst, silence, width); 852 dst += dst_step; 853 } 854 } 855 return 0; 856 } 857 858 int snd_pcm_area_copy(const snd_pcm_channel_area_t *src_area, size_t src_offset, 859 const snd_pcm_channel_area_t *dst_area, size_t dst_offset, 860 size_t samples, int format) 861 { 862 /* FIXME: sub byte resolution and odd dst_offset */ 863 char *src, *dst; 864 int width; 865 int src_step, dst_step; 866 src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8; 867 if (!src_area->addr) 868 return snd_pcm_area_silence(dst_area, dst_offset, samples, format); 869 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; 870 if (!dst_area->addr) 871 return 0; 872 width = snd_pcm_format_physical_width(format); 873 if (width <= 0) 874 return -EINVAL; 875 if (src_area->step == (unsigned int) width && 876 dst_area->step == (unsigned int) width && width >= 8) { 877 size_t bytes = samples * width / 8; 878 memcpy(dst, src, bytes); 879 return 0; 880 } 881 src_step = src_area->step / 8; 882 dst_step = dst_area->step / 8; 883 if (width == 4) { 884 /* Ima ADPCM */ 885 int srcbit = src_area->first % 8; 886 int srcbit_step = src_area->step % 8; 887 int dstbit = dst_area->first % 8; 888 int dstbit_step = dst_area->step % 8; 889 while (samples-- > 0) { 890 unsigned char srcval; 891 if (srcbit) 892 srcval = *src & 0x0f; 893 else 894 srcval = (*src & 0xf0) >> 4; 895 if (dstbit) 896 *dst = (*dst & 0xf0) | srcval; 897 else 898 *dst = (*dst & 0x0f) | (srcval << 4); 899 src += src_step; 900 srcbit += srcbit_step; 901 if (srcbit == 8) { 902 src++; 903 srcbit = 0; 904 } 905 dst += dst_step; 906 dstbit += dstbit_step; 907 if (dstbit == 8) { 908 dst++; 909 dstbit = 0; 910 } 911 } 912 } else { 913 width /= 8; 914 while (samples-- > 0) { 915 memcpy(dst, src, width); 916 src += src_step; 917 dst += dst_step; 918 } 919 } 920 return 0; 921 } 922