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 = kzalloc(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 667 while (1) { 668 err = plugin->src_channels_mask(plugin, dstmask, &srcmask); 669 if (err < 0) 670 return err; 671 dstmask = srcmask; 672 if (plugin->prev == NULL) 673 break; 674 plugin = plugin->prev; 675 } 676 bitset_and(client_vmask, dstmask, plugin->src_format.channels); 677 return 0; 678 } 679 } 680 681 static int snd_pcm_plug_playback_disable_useless_channels(snd_pcm_plug_t *plug, 682 snd_pcm_plugin_channel_t *src_channels) 683 { 684 snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug); 685 unsigned int nchannels = plugin->src_format.channels; 686 bitset_t bs[bitset_size(nchannels)]; 687 bitset_t *srcmask = bs; 688 int err; 689 unsigned int channel; 690 for (channel = 0; channel < nchannels; channel++) { 691 if (src_channels[channel].enabled) 692 bitset_set(srcmask, channel); 693 else 694 bitset_reset(srcmask, channel); 695 } 696 err = snd_pcm_plug_playback_channels_mask(plug, srcmask); 697 if (err < 0) 698 return err; 699 for (channel = 0; channel < nchannels; channel++) { 700 if (!bitset_get(srcmask, channel)) 701 src_channels[channel].enabled = 0; 702 } 703 return 0; 704 } 705 706 static int snd_pcm_plug_capture_disable_useless_channels(snd_pcm_plug_t *plug, 707 snd_pcm_plugin_channel_t *src_channels, 708 snd_pcm_plugin_channel_t *client_channels) 709 { 710 snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug); 711 unsigned int nchannels = plugin->dst_format.channels; 712 bitset_t bs[bitset_size(nchannels)]; 713 bitset_t *dstmask = bs; 714 bitset_t *srcmask; 715 int err; 716 unsigned int channel; 717 for (channel = 0; channel < nchannels; channel++) { 718 if (client_channels[channel].enabled) 719 bitset_set(dstmask, channel); 720 else 721 bitset_reset(dstmask, channel); 722 } 723 while (plugin) { 724 err = plugin->src_channels_mask(plugin, dstmask, &srcmask); 725 if (err < 0) 726 return err; 727 dstmask = srcmask; 728 plugin = plugin->prev; 729 } 730 plugin = snd_pcm_plug_first(plug); 731 nchannels = plugin->src_format.channels; 732 for (channel = 0; channel < nchannels; channel++) { 733 if (!bitset_get(dstmask, channel)) 734 src_channels[channel].enabled = 0; 735 } 736 return 0; 737 } 738 739 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) 740 { 741 snd_pcm_plugin_t *plugin, *next; 742 snd_pcm_plugin_channel_t *dst_channels; 743 int err; 744 snd_pcm_sframes_t frames = size; 745 746 if ((err = snd_pcm_plug_playback_disable_useless_channels(plug, src_channels)) < 0) 747 return err; 748 749 plugin = snd_pcm_plug_first(plug); 750 while (plugin && frames > 0) { 751 if ((next = plugin->next) != NULL) { 752 snd_pcm_sframes_t frames1 = frames; 753 if (plugin->dst_frames) 754 frames1 = plugin->dst_frames(plugin, frames); 755 if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) { 756 return err; 757 } 758 if (err != frames1) { 759 frames = err; 760 if (plugin->src_frames) 761 frames = plugin->src_frames(plugin, frames1); 762 } 763 } else 764 dst_channels = NULL; 765 pdprintf("write plugin: %s, %li\n", plugin->name, frames); 766 if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) 767 return frames; 768 src_channels = dst_channels; 769 plugin = next; 770 } 771 return snd_pcm_plug_client_size(plug, frames); 772 } 773 774 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) 775 { 776 snd_pcm_plugin_t *plugin, *next; 777 snd_pcm_plugin_channel_t *src_channels, *dst_channels; 778 snd_pcm_sframes_t frames = size; 779 int err; 780 781 frames = snd_pcm_plug_slave_size(plug, frames); 782 if (frames < 0) 783 return frames; 784 785 src_channels = NULL; 786 plugin = snd_pcm_plug_first(plug); 787 while (plugin && frames > 0) { 788 if ((next = plugin->next) != NULL) { 789 if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) { 790 return err; 791 } 792 frames = err; 793 if (!plugin->prev) { 794 if ((err = snd_pcm_plug_capture_disable_useless_channels(plug, dst_channels, dst_channels_final)) < 0) 795 return err; 796 } 797 } else { 798 dst_channels = dst_channels_final; 799 } 800 pdprintf("read plugin: %s, %li\n", plugin->name, frames); 801 if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0) 802 return frames; 803 plugin = next; 804 src_channels = dst_channels; 805 } 806 return frames; 807 } 808 809 int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, size_t dst_offset, 810 size_t samples, int format) 811 { 812 /* FIXME: sub byte resolution and odd dst_offset */ 813 unsigned char *dst; 814 unsigned int dst_step; 815 int width; 816 const unsigned char *silence; 817 if (!dst_area->addr) 818 return 0; 819 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; 820 width = snd_pcm_format_physical_width(format); 821 if (width <= 0) 822 return -EINVAL; 823 if (dst_area->step == (unsigned int) width && width >= 8) 824 return snd_pcm_format_set_silence(format, dst, samples); 825 silence = snd_pcm_format_silence_64(format); 826 if (! silence) 827 return -EINVAL; 828 dst_step = dst_area->step / 8; 829 if (width == 4) { 830 /* Ima ADPCM */ 831 int dstbit = dst_area->first % 8; 832 int dstbit_step = dst_area->step % 8; 833 while (samples-- > 0) { 834 if (dstbit) 835 *dst &= 0xf0; 836 else 837 *dst &= 0x0f; 838 dst += dst_step; 839 dstbit += dstbit_step; 840 if (dstbit == 8) { 841 dst++; 842 dstbit = 0; 843 } 844 } 845 } else { 846 width /= 8; 847 while (samples-- > 0) { 848 memcpy(dst, silence, width); 849 dst += dst_step; 850 } 851 } 852 return 0; 853 } 854 855 int snd_pcm_area_copy(const snd_pcm_channel_area_t *src_area, size_t src_offset, 856 const snd_pcm_channel_area_t *dst_area, size_t dst_offset, 857 size_t samples, int format) 858 { 859 /* FIXME: sub byte resolution and odd dst_offset */ 860 char *src, *dst; 861 int width; 862 int src_step, dst_step; 863 src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8; 864 if (!src_area->addr) 865 return snd_pcm_area_silence(dst_area, dst_offset, samples, format); 866 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8; 867 if (!dst_area->addr) 868 return 0; 869 width = snd_pcm_format_physical_width(format); 870 if (width <= 0) 871 return -EINVAL; 872 if (src_area->step == (unsigned int) width && 873 dst_area->step == (unsigned int) width && width >= 8) { 874 size_t bytes = samples * width / 8; 875 memcpy(dst, src, bytes); 876 return 0; 877 } 878 src_step = src_area->step / 8; 879 dst_step = dst_area->step / 8; 880 if (width == 4) { 881 /* Ima ADPCM */ 882 int srcbit = src_area->first % 8; 883 int srcbit_step = src_area->step % 8; 884 int dstbit = dst_area->first % 8; 885 int dstbit_step = dst_area->step % 8; 886 while (samples-- > 0) { 887 unsigned char srcval; 888 if (srcbit) 889 srcval = *src & 0x0f; 890 else 891 srcval = (*src & 0xf0) >> 4; 892 if (dstbit) 893 *dst = (*dst & 0xf0) | srcval; 894 else 895 *dst = (*dst & 0x0f) | (srcval << 4); 896 src += src_step; 897 srcbit += srcbit_step; 898 if (srcbit == 8) { 899 src++; 900 srcbit = 0; 901 } 902 dst += dst_step; 903 dstbit += dstbit_step; 904 if (dstbit == 8) { 905 dst++; 906 dstbit = 0; 907 } 908 } 909 } else { 910 width /= 8; 911 while (samples-- > 0) { 912 memcpy(dst, src, width); 913 src += src_step; 914 dst += dst_step; 915 } 916 } 917 return 0; 918 } 919