0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #if 0
0024 #define PLUGIN_DEBUG
0025 #endif
0026
0027 #include <linux/slab.h>
0028 #include <linux/time.h>
0029 #include <linux/vmalloc.h>
0030 #include <sound/core.h>
0031 #include <sound/pcm.h>
0032 #include <sound/pcm_params.h>
0033 #include "pcm_plugin.h"
0034
0035 #define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first)
0036 #define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last)
0037
0038
0039
0040
0041
0042 static int rate_match(unsigned int src_rate, unsigned int dst_rate)
0043 {
0044 unsigned int low = (src_rate * 95) / 100;
0045 unsigned int high = (src_rate * 105) / 100;
0046 return dst_rate >= low && dst_rate <= high;
0047 }
0048
0049 static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t frames)
0050 {
0051 struct snd_pcm_plugin_format *format;
0052 ssize_t width;
0053 size_t size;
0054 unsigned int channel;
0055 struct snd_pcm_plugin_channel *c;
0056
0057 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0058 format = &plugin->src_format;
0059 } else {
0060 format = &plugin->dst_format;
0061 }
0062 width = snd_pcm_format_physical_width(format->format);
0063 if (width < 0)
0064 return width;
0065 size = array3_size(frames, format->channels, width);
0066
0067 if (size > 1024 * 1024)
0068 return -ENOMEM;
0069 if (snd_BUG_ON(size % 8))
0070 return -ENXIO;
0071 size /= 8;
0072 if (plugin->buf_frames < frames) {
0073 kvfree(plugin->buf);
0074 plugin->buf = kvzalloc(size, GFP_KERNEL);
0075 plugin->buf_frames = frames;
0076 }
0077 if (!plugin->buf) {
0078 plugin->buf_frames = 0;
0079 return -ENOMEM;
0080 }
0081 c = plugin->buf_channels;
0082 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
0083 for (channel = 0; channel < format->channels; channel++, c++) {
0084 c->frames = frames;
0085 c->enabled = 1;
0086 c->wanted = 0;
0087 c->area.addr = plugin->buf;
0088 c->area.first = channel * width;
0089 c->area.step = format->channels * width;
0090 }
0091 } else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
0092 if (snd_BUG_ON(size % format->channels))
0093 return -EINVAL;
0094 size /= format->channels;
0095 for (channel = 0; channel < format->channels; channel++, c++) {
0096 c->frames = frames;
0097 c->enabled = 1;
0098 c->wanted = 0;
0099 c->area.addr = plugin->buf + (channel * size);
0100 c->area.first = 0;
0101 c->area.step = width;
0102 }
0103 } else
0104 return -EINVAL;
0105 return 0;
0106 }
0107
0108 int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
0109 {
0110 int err;
0111 if (snd_BUG_ON(!snd_pcm_plug_first(plug)))
0112 return -ENXIO;
0113 if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) {
0114 struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug);
0115 while (plugin->next) {
0116 if (plugin->dst_frames)
0117 frames = plugin->dst_frames(plugin, frames);
0118 if ((snd_pcm_sframes_t)frames <= 0)
0119 return -ENXIO;
0120 plugin = plugin->next;
0121 err = snd_pcm_plugin_alloc(plugin, frames);
0122 if (err < 0)
0123 return err;
0124 }
0125 } else {
0126 struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
0127 while (plugin->prev) {
0128 if (plugin->src_frames)
0129 frames = plugin->src_frames(plugin, frames);
0130 if ((snd_pcm_sframes_t)frames <= 0)
0131 return -ENXIO;
0132 plugin = plugin->prev;
0133 err = snd_pcm_plugin_alloc(plugin, frames);
0134 if (err < 0)
0135 return err;
0136 }
0137 }
0138 return 0;
0139 }
0140
0141
0142 snd_pcm_sframes_t snd_pcm_plugin_client_channels(struct snd_pcm_plugin *plugin,
0143 snd_pcm_uframes_t frames,
0144 struct snd_pcm_plugin_channel **channels)
0145 {
0146 *channels = plugin->buf_channels;
0147 return frames;
0148 }
0149
0150 int snd_pcm_plugin_build(struct snd_pcm_substream *plug,
0151 const char *name,
0152 struct snd_pcm_plugin_format *src_format,
0153 struct snd_pcm_plugin_format *dst_format,
0154 size_t extra,
0155 struct snd_pcm_plugin **ret)
0156 {
0157 struct snd_pcm_plugin *plugin;
0158 unsigned int channels;
0159
0160 if (snd_BUG_ON(!plug))
0161 return -ENXIO;
0162 if (snd_BUG_ON(!src_format || !dst_format))
0163 return -ENXIO;
0164 plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL);
0165 if (plugin == NULL)
0166 return -ENOMEM;
0167 plugin->name = name;
0168 plugin->plug = plug;
0169 plugin->stream = snd_pcm_plug_stream(plug);
0170 plugin->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
0171 plugin->src_format = *src_format;
0172 plugin->src_width = snd_pcm_format_physical_width(src_format->format);
0173 snd_BUG_ON(plugin->src_width <= 0);
0174 plugin->dst_format = *dst_format;
0175 plugin->dst_width = snd_pcm_format_physical_width(dst_format->format);
0176 snd_BUG_ON(plugin->dst_width <= 0);
0177 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK)
0178 channels = src_format->channels;
0179 else
0180 channels = dst_format->channels;
0181 plugin->buf_channels = kcalloc(channels, sizeof(*plugin->buf_channels), GFP_KERNEL);
0182 if (plugin->buf_channels == NULL) {
0183 snd_pcm_plugin_free(plugin);
0184 return -ENOMEM;
0185 }
0186 plugin->client_channels = snd_pcm_plugin_client_channels;
0187 *ret = plugin;
0188 return 0;
0189 }
0190
0191 int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin)
0192 {
0193 if (! plugin)
0194 return 0;
0195 if (plugin->private_free)
0196 plugin->private_free(plugin);
0197 kfree(plugin->buf_channels);
0198 kvfree(plugin->buf);
0199 kfree(plugin);
0200 return 0;
0201 }
0202
0203 static snd_pcm_sframes_t calc_dst_frames(struct snd_pcm_substream *plug,
0204 snd_pcm_sframes_t frames,
0205 bool check_size)
0206 {
0207 struct snd_pcm_plugin *plugin, *plugin_next;
0208
0209 plugin = snd_pcm_plug_first(plug);
0210 while (plugin && frames > 0) {
0211 plugin_next = plugin->next;
0212 if (check_size && plugin->buf_frames &&
0213 frames > plugin->buf_frames)
0214 frames = plugin->buf_frames;
0215 if (plugin->dst_frames) {
0216 frames = plugin->dst_frames(plugin, frames);
0217 if (frames < 0)
0218 return frames;
0219 }
0220 plugin = plugin_next;
0221 }
0222 return frames;
0223 }
0224
0225 static snd_pcm_sframes_t calc_src_frames(struct snd_pcm_substream *plug,
0226 snd_pcm_sframes_t frames,
0227 bool check_size)
0228 {
0229 struct snd_pcm_plugin *plugin, *plugin_prev;
0230
0231 plugin = snd_pcm_plug_last(plug);
0232 while (plugin && frames > 0) {
0233 plugin_prev = plugin->prev;
0234 if (plugin->src_frames) {
0235 frames = plugin->src_frames(plugin, frames);
0236 if (frames < 0)
0237 return frames;
0238 }
0239 if (check_size && plugin->buf_frames &&
0240 frames > plugin->buf_frames)
0241 frames = plugin->buf_frames;
0242 plugin = plugin_prev;
0243 }
0244 return frames;
0245 }
0246
0247 snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t drv_frames)
0248 {
0249 if (snd_BUG_ON(!plug))
0250 return -ENXIO;
0251 switch (snd_pcm_plug_stream(plug)) {
0252 case SNDRV_PCM_STREAM_PLAYBACK:
0253 return calc_src_frames(plug, drv_frames, false);
0254 case SNDRV_PCM_STREAM_CAPTURE:
0255 return calc_dst_frames(plug, drv_frames, false);
0256 default:
0257 snd_BUG();
0258 return -EINVAL;
0259 }
0260 }
0261
0262 snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pcm_uframes_t clt_frames)
0263 {
0264 if (snd_BUG_ON(!plug))
0265 return -ENXIO;
0266 switch (snd_pcm_plug_stream(plug)) {
0267 case SNDRV_PCM_STREAM_PLAYBACK:
0268 return calc_dst_frames(plug, clt_frames, false);
0269 case SNDRV_PCM_STREAM_CAPTURE:
0270 return calc_src_frames(plug, clt_frames, false);
0271 default:
0272 snd_BUG();
0273 return -EINVAL;
0274 }
0275 }
0276
0277 static int snd_pcm_plug_formats(const struct snd_mask *mask,
0278 snd_pcm_format_t format)
0279 {
0280 struct snd_mask formats = *mask;
0281 u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
0282 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
0283 SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE |
0284 SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE |
0285 SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE |
0286 SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_S24_3LE |
0287 SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE |
0288 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE |
0289 SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
0290 snd_mask_set(&formats, (__force int)SNDRV_PCM_FORMAT_MU_LAW);
0291
0292 if (formats.bits[0] & lower_32_bits(linfmts))
0293 formats.bits[0] |= lower_32_bits(linfmts);
0294 if (formats.bits[1] & upper_32_bits(linfmts))
0295 formats.bits[1] |= upper_32_bits(linfmts);
0296 return snd_mask_test(&formats, (__force int)format);
0297 }
0298
0299 static const snd_pcm_format_t preferred_formats[] = {
0300 SNDRV_PCM_FORMAT_S16_LE,
0301 SNDRV_PCM_FORMAT_S16_BE,
0302 SNDRV_PCM_FORMAT_U16_LE,
0303 SNDRV_PCM_FORMAT_U16_BE,
0304 SNDRV_PCM_FORMAT_S24_3LE,
0305 SNDRV_PCM_FORMAT_S24_3BE,
0306 SNDRV_PCM_FORMAT_U24_3LE,
0307 SNDRV_PCM_FORMAT_U24_3BE,
0308 SNDRV_PCM_FORMAT_S24_LE,
0309 SNDRV_PCM_FORMAT_S24_BE,
0310 SNDRV_PCM_FORMAT_U24_LE,
0311 SNDRV_PCM_FORMAT_U24_BE,
0312 SNDRV_PCM_FORMAT_S32_LE,
0313 SNDRV_PCM_FORMAT_S32_BE,
0314 SNDRV_PCM_FORMAT_U32_LE,
0315 SNDRV_PCM_FORMAT_U32_BE,
0316 SNDRV_PCM_FORMAT_S8,
0317 SNDRV_PCM_FORMAT_U8
0318 };
0319
0320 snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
0321 const struct snd_mask *format_mask)
0322 {
0323 int i;
0324
0325 if (snd_mask_test(format_mask, (__force int)format))
0326 return format;
0327 if (!snd_pcm_plug_formats(format_mask, format))
0328 return (__force snd_pcm_format_t)-EINVAL;
0329 if (snd_pcm_format_linear(format)) {
0330 unsigned int width = snd_pcm_format_width(format);
0331 int unsignd = snd_pcm_format_unsigned(format) > 0;
0332 int big = snd_pcm_format_big_endian(format) > 0;
0333 unsigned int badness, best = -1;
0334 snd_pcm_format_t best_format = (__force snd_pcm_format_t)-1;
0335 for (i = 0; i < ARRAY_SIZE(preferred_formats); i++) {
0336 snd_pcm_format_t f = preferred_formats[i];
0337 unsigned int w;
0338 if (!snd_mask_test(format_mask, (__force int)f))
0339 continue;
0340 w = snd_pcm_format_width(f);
0341 if (w >= width)
0342 badness = w - width;
0343 else
0344 badness = width - w + 32;
0345 badness += snd_pcm_format_unsigned(f) != unsignd;
0346 badness += snd_pcm_format_big_endian(f) != big;
0347 if (badness < best) {
0348 best_format = f;
0349 best = badness;
0350 }
0351 }
0352 if ((__force int)best_format >= 0)
0353 return best_format;
0354 else
0355 return (__force snd_pcm_format_t)-EINVAL;
0356 } else {
0357 switch (format) {
0358 case SNDRV_PCM_FORMAT_MU_LAW:
0359 for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) {
0360 snd_pcm_format_t format1 = preferred_formats[i];
0361 if (snd_mask_test(format_mask, (__force int)format1))
0362 return format1;
0363 }
0364 fallthrough;
0365 default:
0366 return (__force snd_pcm_format_t)-EINVAL;
0367 }
0368 }
0369 }
0370
0371 int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
0372 struct snd_pcm_hw_params *params,
0373 struct snd_pcm_hw_params *slave_params)
0374 {
0375 struct snd_pcm_plugin_format tmpformat;
0376 struct snd_pcm_plugin_format dstformat;
0377 struct snd_pcm_plugin_format srcformat;
0378 snd_pcm_access_t src_access, dst_access;
0379 struct snd_pcm_plugin *plugin = NULL;
0380 int err;
0381 int stream = snd_pcm_plug_stream(plug);
0382 int slave_interleaved = (params_channels(slave_params) == 1 ||
0383 params_access(slave_params) == SNDRV_PCM_ACCESS_RW_INTERLEAVED);
0384
0385 switch (stream) {
0386 case SNDRV_PCM_STREAM_PLAYBACK:
0387 dstformat.format = params_format(slave_params);
0388 dstformat.rate = params_rate(slave_params);
0389 dstformat.channels = params_channels(slave_params);
0390 srcformat.format = params_format(params);
0391 srcformat.rate = params_rate(params);
0392 srcformat.channels = params_channels(params);
0393 src_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
0394 dst_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
0395 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
0396 break;
0397 case SNDRV_PCM_STREAM_CAPTURE:
0398 dstformat.format = params_format(params);
0399 dstformat.rate = params_rate(params);
0400 dstformat.channels = params_channels(params);
0401 srcformat.format = params_format(slave_params);
0402 srcformat.rate = params_rate(slave_params);
0403 srcformat.channels = params_channels(slave_params);
0404 src_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
0405 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
0406 dst_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
0407 break;
0408 default:
0409 snd_BUG();
0410 return -EINVAL;
0411 }
0412 tmpformat = srcformat;
0413
0414 pdprintf("srcformat: format=%i, rate=%i, channels=%i\n",
0415 srcformat.format,
0416 srcformat.rate,
0417 srcformat.channels);
0418 pdprintf("dstformat: format=%i, rate=%i, channels=%i\n",
0419 dstformat.format,
0420 dstformat.rate,
0421 dstformat.channels);
0422
0423
0424 if (! rate_match(srcformat.rate, dstformat.rate) &&
0425 ! snd_pcm_format_linear(srcformat.format)) {
0426 if (srcformat.format != SNDRV_PCM_FORMAT_MU_LAW)
0427 return -EINVAL;
0428 tmpformat.format = SNDRV_PCM_FORMAT_S16;
0429 err = snd_pcm_plugin_build_mulaw(plug,
0430 &srcformat, &tmpformat,
0431 &plugin);
0432 if (err < 0)
0433 return err;
0434 err = snd_pcm_plugin_append(plugin);
0435 if (err < 0) {
0436 snd_pcm_plugin_free(plugin);
0437 return err;
0438 }
0439 srcformat = tmpformat;
0440 src_access = dst_access;
0441 }
0442
0443
0444 if (srcformat.channels > dstformat.channels) {
0445 tmpformat.channels = dstformat.channels;
0446 err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
0447 pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
0448 if (err < 0)
0449 return err;
0450 err = snd_pcm_plugin_append(plugin);
0451 if (err < 0) {
0452 snd_pcm_plugin_free(plugin);
0453 return err;
0454 }
0455 srcformat = tmpformat;
0456 src_access = dst_access;
0457 }
0458
0459
0460 if (!rate_match(srcformat.rate, dstformat.rate)) {
0461 if (srcformat.format != SNDRV_PCM_FORMAT_S16) {
0462
0463 tmpformat.format = SNDRV_PCM_FORMAT_S16;
0464 err = snd_pcm_plugin_build_linear(plug,
0465 &srcformat, &tmpformat,
0466 &plugin);
0467 if (err < 0)
0468 return err;
0469 err = snd_pcm_plugin_append(plugin);
0470 if (err < 0) {
0471 snd_pcm_plugin_free(plugin);
0472 return err;
0473 }
0474 srcformat = tmpformat;
0475 src_access = dst_access;
0476 }
0477 tmpformat.rate = dstformat.rate;
0478 err = snd_pcm_plugin_build_rate(plug,
0479 &srcformat, &tmpformat,
0480 &plugin);
0481 pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err);
0482 if (err < 0)
0483 return err;
0484 err = snd_pcm_plugin_append(plugin);
0485 if (err < 0) {
0486 snd_pcm_plugin_free(plugin);
0487 return err;
0488 }
0489 srcformat = tmpformat;
0490 src_access = dst_access;
0491 }
0492
0493
0494 if (srcformat.format != dstformat.format) {
0495 tmpformat.format = dstformat.format;
0496 if (srcformat.format == SNDRV_PCM_FORMAT_MU_LAW ||
0497 tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
0498 err = snd_pcm_plugin_build_mulaw(plug,
0499 &srcformat, &tmpformat,
0500 &plugin);
0501 }
0502 else if (snd_pcm_format_linear(srcformat.format) &&
0503 snd_pcm_format_linear(tmpformat.format)) {
0504 err = snd_pcm_plugin_build_linear(plug,
0505 &srcformat, &tmpformat,
0506 &plugin);
0507 }
0508 else
0509 return -EINVAL;
0510 pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err);
0511 if (err < 0)
0512 return err;
0513 err = snd_pcm_plugin_append(plugin);
0514 if (err < 0) {
0515 snd_pcm_plugin_free(plugin);
0516 return err;
0517 }
0518 srcformat = tmpformat;
0519 src_access = dst_access;
0520 }
0521
0522
0523 if (srcformat.channels < dstformat.channels) {
0524 tmpformat.channels = dstformat.channels;
0525 err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
0526 pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
0527 if (err < 0)
0528 return err;
0529 err = snd_pcm_plugin_append(plugin);
0530 if (err < 0) {
0531 snd_pcm_plugin_free(plugin);
0532 return err;
0533 }
0534 srcformat = tmpformat;
0535 src_access = dst_access;
0536 }
0537
0538
0539 if (src_access != dst_access) {
0540 err = snd_pcm_plugin_build_copy(plug,
0541 &srcformat,
0542 &tmpformat,
0543 &plugin);
0544 pdprintf("interleave change (copy: returns %i)\n", err);
0545 if (err < 0)
0546 return err;
0547 err = snd_pcm_plugin_append(plugin);
0548 if (err < 0) {
0549 snd_pcm_plugin_free(plugin);
0550 return err;
0551 }
0552 }
0553
0554 return 0;
0555 }
0556
0557 snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plug,
0558 char *buf,
0559 snd_pcm_uframes_t count,
0560 struct snd_pcm_plugin_channel **channels)
0561 {
0562 struct snd_pcm_plugin *plugin;
0563 struct snd_pcm_plugin_channel *v;
0564 struct snd_pcm_plugin_format *format;
0565 int width, nchannels, channel;
0566 int stream = snd_pcm_plug_stream(plug);
0567
0568 if (snd_BUG_ON(!buf))
0569 return -ENXIO;
0570 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
0571 plugin = snd_pcm_plug_first(plug);
0572 format = &plugin->src_format;
0573 } else {
0574 plugin = snd_pcm_plug_last(plug);
0575 format = &plugin->dst_format;
0576 }
0577 v = plugin->buf_channels;
0578 *channels = v;
0579 width = snd_pcm_format_physical_width(format->format);
0580 if (width < 0)
0581 return width;
0582 nchannels = format->channels;
0583 if (snd_BUG_ON(plugin->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
0584 format->channels > 1))
0585 return -ENXIO;
0586 for (channel = 0; channel < nchannels; channel++, v++) {
0587 v->frames = count;
0588 v->enabled = 1;
0589 v->wanted = (stream == SNDRV_PCM_STREAM_CAPTURE);
0590 v->area.addr = buf;
0591 v->area.first = channel * width;
0592 v->area.step = nchannels * width;
0593 }
0594 return count;
0595 }
0596
0597 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)
0598 {
0599 struct snd_pcm_plugin *plugin, *next;
0600 struct snd_pcm_plugin_channel *dst_channels;
0601 int err;
0602 snd_pcm_sframes_t frames = size;
0603
0604 plugin = snd_pcm_plug_first(plug);
0605 while (plugin) {
0606 if (frames <= 0)
0607 return frames;
0608 next = plugin->next;
0609 if (next) {
0610 snd_pcm_sframes_t frames1 = frames;
0611 if (plugin->dst_frames) {
0612 frames1 = plugin->dst_frames(plugin, frames);
0613 if (frames1 <= 0)
0614 return frames1;
0615 }
0616 err = next->client_channels(next, frames1, &dst_channels);
0617 if (err < 0)
0618 return err;
0619 if (err != frames1) {
0620 frames = err;
0621 if (plugin->src_frames) {
0622 frames = plugin->src_frames(plugin, frames1);
0623 if (frames <= 0)
0624 return frames;
0625 }
0626 }
0627 } else
0628 dst_channels = NULL;
0629 pdprintf("write plugin: %s, %li\n", plugin->name, frames);
0630 frames = plugin->transfer(plugin, src_channels, dst_channels, frames);
0631 if (frames < 0)
0632 return frames;
0633 src_channels = dst_channels;
0634 plugin = next;
0635 }
0636 return calc_src_frames(plug, frames, true);
0637 }
0638
0639 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)
0640 {
0641 struct snd_pcm_plugin *plugin, *next;
0642 struct snd_pcm_plugin_channel *src_channels, *dst_channels;
0643 snd_pcm_sframes_t frames = size;
0644 int err;
0645
0646 frames = calc_src_frames(plug, frames, true);
0647 if (frames < 0)
0648 return frames;
0649
0650 src_channels = NULL;
0651 plugin = snd_pcm_plug_first(plug);
0652 while (plugin && frames > 0) {
0653 next = plugin->next;
0654 if (next) {
0655 err = plugin->client_channels(plugin, frames, &dst_channels);
0656 if (err < 0)
0657 return err;
0658 frames = err;
0659 } else {
0660 dst_channels = dst_channels_final;
0661 }
0662 pdprintf("read plugin: %s, %li\n", plugin->name, frames);
0663 frames = plugin->transfer(plugin, src_channels, dst_channels, frames);
0664 if (frames < 0)
0665 return frames;
0666 plugin = next;
0667 src_channels = dst_channels;
0668 }
0669 return frames;
0670 }
0671
0672 int snd_pcm_area_silence(const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
0673 size_t samples, snd_pcm_format_t format)
0674 {
0675
0676 unsigned char *dst;
0677 unsigned int dst_step;
0678 int width;
0679 const unsigned char *silence;
0680 if (!dst_area->addr)
0681 return 0;
0682 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
0683 width = snd_pcm_format_physical_width(format);
0684 if (width <= 0)
0685 return -EINVAL;
0686 if (dst_area->step == (unsigned int) width && width >= 8)
0687 return snd_pcm_format_set_silence(format, dst, samples);
0688 silence = snd_pcm_format_silence_64(format);
0689 if (! silence)
0690 return -EINVAL;
0691 dst_step = dst_area->step / 8;
0692 if (width == 4) {
0693
0694 int dstbit = dst_area->first % 8;
0695 int dstbit_step = dst_area->step % 8;
0696 while (samples-- > 0) {
0697 if (dstbit)
0698 *dst &= 0xf0;
0699 else
0700 *dst &= 0x0f;
0701 dst += dst_step;
0702 dstbit += dstbit_step;
0703 if (dstbit == 8) {
0704 dst++;
0705 dstbit = 0;
0706 }
0707 }
0708 } else {
0709 width /= 8;
0710 while (samples-- > 0) {
0711 memcpy(dst, silence, width);
0712 dst += dst_step;
0713 }
0714 }
0715 return 0;
0716 }
0717
0718 int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_area, size_t src_offset,
0719 const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
0720 size_t samples, snd_pcm_format_t format)
0721 {
0722
0723 char *src, *dst;
0724 int width;
0725 int src_step, dst_step;
0726 src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8;
0727 if (!src_area->addr)
0728 return snd_pcm_area_silence(dst_area, dst_offset, samples, format);
0729 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
0730 if (!dst_area->addr)
0731 return 0;
0732 width = snd_pcm_format_physical_width(format);
0733 if (width <= 0)
0734 return -EINVAL;
0735 if (src_area->step == (unsigned int) width &&
0736 dst_area->step == (unsigned int) width && width >= 8) {
0737 size_t bytes = samples * width / 8;
0738 memcpy(dst, src, bytes);
0739 return 0;
0740 }
0741 src_step = src_area->step / 8;
0742 dst_step = dst_area->step / 8;
0743 if (width == 4) {
0744
0745 int srcbit = src_area->first % 8;
0746 int srcbit_step = src_area->step % 8;
0747 int dstbit = dst_area->first % 8;
0748 int dstbit_step = dst_area->step % 8;
0749 while (samples-- > 0) {
0750 unsigned char srcval;
0751 if (srcbit)
0752 srcval = *src & 0x0f;
0753 else
0754 srcval = (*src & 0xf0) >> 4;
0755 if (dstbit)
0756 *dst = (*dst & 0xf0) | srcval;
0757 else
0758 *dst = (*dst & 0x0f) | (srcval << 4);
0759 src += src_step;
0760 srcbit += srcbit_step;
0761 if (srcbit == 8) {
0762 src++;
0763 srcbit = 0;
0764 }
0765 dst += dst_step;
0766 dstbit += dstbit_step;
0767 if (dstbit == 8) {
0768 dst++;
0769 dstbit = 0;
0770 }
0771 }
0772 } else {
0773 width /= 8;
0774 while (samples-- > 0) {
0775 memcpy(dst, src, width);
0776 src += src_step;
0777 dst += dst_step;
0778 }
0779 }
0780 return 0;
0781 }