aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/oss/pcm_plugin.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-23 23:44:19 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-23 23:44:19 -0500
commit1ebbe2b20091d306453a5cf480a87e6cd28ae76f (patch)
treef5cd7a0fa69b8b1938cb5a0faed2e7b0628072a5 /sound/core/oss/pcm_plugin.c
parentac58c9059da8886b5e8cde012a80266b18ca146e (diff)
parent674a396c6d2ba0341ebdd7c1c9950f32f018e2dd (diff)
Merge branch 'linus'
Diffstat (limited to 'sound/core/oss/pcm_plugin.c')
-rw-r--r--sound/core/oss/pcm_plugin.c272
1 files changed, 49 insertions, 223 deletions
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
index 7e8676880dde..0e67dd280a5d 100644
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -25,6 +25,9 @@
25#endif 25#endif
26 26
27#include <sound/driver.h> 27#include <sound/driver.h>
28
29#ifdef CONFIG_SND_PCM_OSS_PLUGINS
30
28#include <linux/slab.h> 31#include <linux/slab.h>
29#include <linux/time.h> 32#include <linux/time.h>
30#include <linux/vmalloc.h> 33#include <linux/vmalloc.h>
@@ -36,26 +39,6 @@
36#define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first) 39#define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first)
37#define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last) 40#define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last)
38 41
39static int snd_pcm_plugin_src_channels_mask(struct snd_pcm_plugin *plugin,
40 unsigned long *dst_vmask,
41 unsigned long **src_vmask)
42{
43 unsigned long *vmask = plugin->src_vmask;
44 bitmap_copy(vmask, dst_vmask, plugin->src_format.channels);
45 *src_vmask = vmask;
46 return 0;
47}
48
49static int snd_pcm_plugin_dst_channels_mask(struct snd_pcm_plugin *plugin,
50 unsigned long *src_vmask,
51 unsigned long **dst_vmask)
52{
53 unsigned long *vmask = plugin->dst_vmask;
54 bitmap_copy(vmask, src_vmask, plugin->dst_format.channels);
55 *dst_vmask = vmask;
56 return 0;
57}
58
59/* 42/*
60 * because some cards might have rates "very close", we ignore 43 * because some cards might have rates "very close", we ignore
61 * all "resampling" requests within +-5% 44 * all "resampling" requests within +-5%
@@ -193,19 +176,7 @@ int snd_pcm_plugin_build(struct snd_pcm_substream *plug,
193 snd_pcm_plugin_free(plugin); 176 snd_pcm_plugin_free(plugin);
194 return -ENOMEM; 177 return -ENOMEM;
195 } 178 }
196 plugin->src_vmask = bitmap_alloc(src_format->channels);
197 if (plugin->src_vmask == NULL) {
198 snd_pcm_plugin_free(plugin);
199 return -ENOMEM;
200 }
201 plugin->dst_vmask = bitmap_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; 179 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; 180 *ret = plugin;
210 return 0; 181 return 0;
211} 182}
@@ -218,8 +189,6 @@ int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin)
218 plugin->private_free(plugin); 189 plugin->private_free(plugin);
219 kfree(plugin->buf_channels); 190 kfree(plugin->buf_channels);
220 vfree(plugin->buf); 191 vfree(plugin->buf);
221 kfree(plugin->src_vmask);
222 kfree(plugin->dst_vmask);
223 kfree(plugin); 192 kfree(plugin);
224 return 0; 193 return 0;
225} 194}
@@ -429,24 +398,14 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
429 dstformat.channels); 398 dstformat.channels);
430 399
431 /* Format change (linearization) */ 400 /* Format change (linearization) */
432 if ((srcformat.format != dstformat.format || 401 if (! rate_match(srcformat.rate, dstformat.rate) &&
433 !rate_match(srcformat.rate, dstformat.rate) || 402 ! snd_pcm_format_linear(srcformat.format)) {
434 srcformat.channels != dstformat.channels) && 403 if (srcformat.format != SNDRV_PCM_FORMAT_MU_LAW)
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; 404 return -EINVAL;
448 } 405 tmpformat.format = SNDRV_PCM_FORMAT_S16;
449 pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err); 406 err = snd_pcm_plugin_build_mulaw(plug,
407 &srcformat, &tmpformat,
408 &plugin);
450 if (err < 0) 409 if (err < 0)
451 return err; 410 return err;
452 err = snd_pcm_plugin_append(plugin); 411 err = snd_pcm_plugin_append(plugin);
@@ -460,35 +419,11 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
460 419
461 /* channels reduction */ 420 /* channels reduction */
462 if (srcformat.channels > dstformat.channels) { 421 if (srcformat.channels > dstformat.channels) {
463 int sv = srcformat.channels;
464 int dv = dstformat.channels;
465 int *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; 422 tmpformat.channels = dstformat.channels;
480 if (rate_match(srcformat.rate, dstformat.rate) && 423 err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
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); 424 pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
488 if (err < 0) { 425 if (err < 0)
489 snd_pcm_plugin_free(plugin);
490 return err; 426 return err;
491 }
492 err = snd_pcm_plugin_append(plugin); 427 err = snd_pcm_plugin_append(plugin);
493 if (err < 0) { 428 if (err < 0) {
494 snd_pcm_plugin_free(plugin); 429 snd_pcm_plugin_free(plugin);
@@ -500,18 +435,29 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
500 435
501 /* rate resampling */ 436 /* rate resampling */
502 if (!rate_match(srcformat.rate, dstformat.rate)) { 437 if (!rate_match(srcformat.rate, dstformat.rate)) {
438 if (srcformat.format != SNDRV_PCM_FORMAT_S16) {
439 /* convert to S16 for resampling */
440 tmpformat.format = SNDRV_PCM_FORMAT_S16;
441 err = snd_pcm_plugin_build_linear(plug,
442 &srcformat, &tmpformat,
443 &plugin);
444 if (err < 0)
445 return err;
446 err = snd_pcm_plugin_append(plugin);
447 if (err < 0) {
448 snd_pcm_plugin_free(plugin);
449 return err;
450 }
451 srcformat = tmpformat;
452 src_access = dst_access;
453 }
503 tmpformat.rate = dstformat.rate; 454 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, 455 err = snd_pcm_plugin_build_rate(plug,
508 &srcformat, &tmpformat, 456 &srcformat, &tmpformat,
509 &plugin); 457 &plugin);
510 pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err); 458 pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err);
511 if (err < 0) { 459 if (err < 0)
512 snd_pcm_plugin_free(plugin);
513 return err; 460 return err;
514 }
515 err = snd_pcm_plugin_append(plugin); 461 err = snd_pcm_plugin_append(plugin);
516 if (err < 0) { 462 if (err < 0) {
517 snd_pcm_plugin_free(plugin); 463 snd_pcm_plugin_free(plugin);
@@ -521,56 +467,11 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
521 src_access = dst_access; 467 src_access = dst_access;
522 } 468 }
523 469
524 /* channels extension */
525 if (srcformat.channels < dstformat.channels) {
526 int sv = srcformat.channels;
527 int dv = dstformat.channels;
528 int *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 */ 470 /* format change */
571 if (srcformat.format != dstformat.format) { 471 if (srcformat.format != dstformat.format) {
572 tmpformat.format = dstformat.format; 472 tmpformat.format = dstformat.format;
573 if (tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) { 473 if (srcformat.format == SNDRV_PCM_FORMAT_MU_LAW ||
474 tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
574 err = snd_pcm_plugin_build_mulaw(plug, 475 err = snd_pcm_plugin_build_mulaw(plug,
575 &srcformat, &tmpformat, 476 &srcformat, &tmpformat,
576 &plugin); 477 &plugin);
@@ -595,6 +496,22 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
595 src_access = dst_access; 496 src_access = dst_access;
596 } 497 }
597 498
499 /* channels extension */
500 if (srcformat.channels < dstformat.channels) {
501 tmpformat.channels = dstformat.channels;
502 err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
503 pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
504 if (err < 0)
505 return err;
506 err = snd_pcm_plugin_append(plugin);
507 if (err < 0) {
508 snd_pcm_plugin_free(plugin);
509 return err;
510 }
511 srcformat = tmpformat;
512 src_access = dst_access;
513 }
514
598 /* de-interleave */ 515 /* de-interleave */
599 if (src_access != dst_access) { 516 if (src_access != dst_access) {
600 err = snd_pcm_plugin_build_copy(plug, 517 err = snd_pcm_plugin_build_copy(plug,
@@ -650,92 +567,6 @@ snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plu
650 return count; 567 return count;
651} 568}
652 569
653static int snd_pcm_plug_playback_channels_mask(struct snd_pcm_substream *plug,
654 unsigned long *client_vmask)
655{
656 struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
657 if (plugin == NULL) {
658 return 0;
659 } else {
660 int schannels = plugin->dst_format.channels;
661 DECLARE_BITMAP(bs, schannels);
662 unsigned long *srcmask;
663 unsigned long *dstmask = bs;
664 int err;
665 bitmap_fill(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 bitmap_and(client_vmask, client_vmask, dstmask, plugin->src_format.channels);
677 return 0;
678 }
679}
680
681static int snd_pcm_plug_playback_disable_useless_channels(struct snd_pcm_substream *plug,
682 struct snd_pcm_plugin_channel *src_channels)
683{
684 struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug);
685 unsigned int nchannels = plugin->src_format.channels;
686 DECLARE_BITMAP(bs, nchannels);
687 unsigned long *srcmask = bs;
688 int err;
689 unsigned int channel;
690 for (channel = 0; channel < nchannels; channel++) {
691 if (src_channels[channel].enabled)
692 set_bit(channel, srcmask);
693 else
694 clear_bit(channel, srcmask);
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 (!test_bit(channel, srcmask))
701 src_channels[channel].enabled = 0;
702 }
703 return 0;
704}
705
706static int snd_pcm_plug_capture_disable_useless_channels(struct snd_pcm_substream *plug,
707 struct snd_pcm_plugin_channel *src_channels,
708 struct snd_pcm_plugin_channel *client_channels)
709{
710 struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
711 unsigned int nchannels = plugin->dst_format.channels;
712 DECLARE_BITMAP(bs, nchannels);
713 unsigned long *dstmask = bs;
714 unsigned long *srcmask;
715 int err;
716 unsigned int channel;
717 for (channel = 0; channel < nchannels; channel++) {
718 if (client_channels[channel].enabled)
719 set_bit(channel, dstmask);
720 else
721 clear_bit(channel, dstmask);
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 (!test_bit(channel, dstmask))
734 src_channels[channel].enabled = 0;
735 }
736 return 0;
737}
738
739snd_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) 570snd_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)
740{ 571{
741 struct snd_pcm_plugin *plugin, *next; 572 struct snd_pcm_plugin *plugin, *next;
@@ -743,9 +574,6 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st
743 int err; 574 int err;
744 snd_pcm_sframes_t frames = size; 575 snd_pcm_sframes_t frames = size;
745 576
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); 577 plugin = snd_pcm_plug_first(plug);
750 while (plugin && frames > 0) { 578 while (plugin && frames > 0) {
751 if ((next = plugin->next) != NULL) { 579 if ((next = plugin->next) != NULL) {
@@ -790,10 +618,6 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str
790 return err; 618 return err;
791 } 619 }
792 frames = err; 620 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 { 621 } else {
798 dst_channels = dst_channels_final; 622 dst_channels = dst_channels_final;
799 } 623 }
@@ -916,3 +740,5 @@ int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_area, size_t src_of
916 } 740 }
917 return 0; 741 return 0;
918} 742}
743
744#endif