diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-23 23:44:19 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-23 23:44:19 -0500 |
commit | 1ebbe2b20091d306453a5cf480a87e6cd28ae76f (patch) | |
tree | f5cd7a0fa69b8b1938cb5a0faed2e7b0628072a5 /sound/core/oss/pcm_plugin.c | |
parent | ac58c9059da8886b5e8cde012a80266b18ca146e (diff) | |
parent | 674a396c6d2ba0341ebdd7c1c9950f32f018e2dd (diff) |
Merge branch 'linus'
Diffstat (limited to 'sound/core/oss/pcm_plugin.c')
-rw-r--r-- | sound/core/oss/pcm_plugin.c | 272 |
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 | ||
39 | static 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 | |||
49 | static 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 | ||
653 | static 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 | |||
681 | static 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 | |||
706 | static 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 | |||
739 | 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) | 570 | 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) |
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 | ||