| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: ossaudio.c,v 1.41 2020/04/15 16:39:06 nia Exp $ */ | | 1 | /* $NetBSD: ossaudio.c,v 1.42 2020/04/19 11:27:40 nia Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1997 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1997 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -17,62 +17,66 @@ | | | @@ -17,62 +17,66 @@ |
17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | * POSSIBILITY OF SUCH DAMAGE. | | 26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | __RCSID("$NetBSD: ossaudio.c,v 1.41 2020/04/15 16:39:06 nia Exp $"); | | 30 | __RCSID("$NetBSD: ossaudio.c,v 1.42 2020/04/19 11:27:40 nia Exp $"); |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * This is an OSS (Linux) sound API emulator. | | 33 | * This is an OSS (Linux) sound API emulator. |
34 | * It provides the essentials of the API. | | 34 | * It provides the essentials of the API. |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | /* XXX This file is essentially the same as sys/compat/ossaudio.c. | | 37 | /* XXX This file is essentially the same as sys/compat/ossaudio.c. |
38 | * With some preprocessor magic it could be the same file. | | 38 | * With some preprocessor magic it could be the same file. |
39 | */ | | 39 | */ |
40 | | | 40 | |
41 | #include <string.h> | | 41 | #include <string.h> |
42 | #include <sys/types.h> | | 42 | #include <sys/types.h> |
43 | #include <sys/ioctl.h> | | 43 | #include <sys/ioctl.h> |
44 | #include <sys/audioio.h> | | 44 | #include <sys/audioio.h> |
45 | #include <sys/stat.h> | | 45 | #include <sys/stat.h> |
46 | #include <errno.h> | | 46 | #include <errno.h> |
47 | #include <fcntl.h> | | 47 | #include <fcntl.h> |
48 | #include <stdio.h> | | 48 | #include <stdio.h> |
49 | #include <unistd.h> | | 49 | #include <unistd.h> |
50 | #include <stdarg.h> | | 50 | #include <stdarg.h> |
| | | 51 | #include <stdbool.h> |
51 | | | 52 | |
52 | #include "soundcard.h" | | 53 | #include "soundcard.h" |
53 | #undef ioctl | | 54 | #undef ioctl |
54 | | | 55 | |
55 | #define GET_DEV(com) ((com) & 0xff) | | 56 | #define GET_DEV(com) ((com) & 0xff) |
56 | | | 57 | |
57 | #define TO_OSSVOL(x) (((x) * 100 + 127) / 255) | | 58 | #define TO_OSSVOL(x) (((x) * 100 + 127) / 255) |
58 | #define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100) | | 59 | #define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100) |
59 | | | 60 | |
60 | #define GETPRINFO(info, name) \ | | 61 | #define GETPRINFO(info, name) \ |
61 | (((info)->mode == AUMODE_RECORD) \ | | 62 | (((info)->mode == AUMODE_RECORD) \ |
62 | ? (info)->record.name : (info)->play.name) | | 63 | ? (info)->record.name : (info)->play.name) |
63 | | | 64 | |
64 | static struct audiodevinfo *getdevinfo(int); | | 65 | static struct audiodevinfo *getdevinfo(int); |
65 | | | 66 | |
| | | 67 | static int getvol(u_int, u_char); |
| | | 68 | static void setvol(int, int, bool); |
| | | 69 | |
66 | static void setchannels(int, int, int); | | 70 | static void setchannels(int, int, int); |
67 | static void setblocksize(int, struct audio_info *); | | 71 | static void setblocksize(int, struct audio_info *); |
68 | | | 72 | |
69 | static int audio_ioctl(int, unsigned long, void *); | | 73 | static int audio_ioctl(int, unsigned long, void *); |
70 | static int mixer_ioctl(int, unsigned long, void *); | | 74 | static int mixer_ioctl(int, unsigned long, void *); |
71 | static int opaque_to_enum(struct audiodevinfo *, audio_mixer_name_t *, int); | | 75 | static int opaque_to_enum(struct audiodevinfo *, audio_mixer_name_t *, int); |
72 | static int enum_to_ord(struct audiodevinfo *, int); | | 76 | static int enum_to_ord(struct audiodevinfo *, int); |
73 | static int enum_to_mask(struct audiodevinfo *, int); | | 77 | static int enum_to_mask(struct audiodevinfo *, int); |
74 | | | 78 | |
75 | #define INTARG (*(int*)argp) | | 79 | #define INTARG (*(int*)argp) |
76 | | | 80 | |
77 | int | | 81 | int |
78 | _oss_ioctl(int fd, unsigned long com, ...) | | 82 | _oss_ioctl(int fd, unsigned long com, ...) |
| @@ -625,61 +629,43 @@ audio_ioctl(int fd, unsigned long com, v | | | @@ -625,61 +629,43 @@ audio_ioctl(int fd, unsigned long com, v |
625 | tmpaudioinfo->max_rate = tmpinfo.play.sample_rate; | | 629 | tmpaudioinfo->max_rate = tmpinfo.play.sample_rate; |
626 | tmpaudioinfo->nrates = 2; | | 630 | tmpaudioinfo->nrates = 2; |
627 | for (i = 0; i < tmpaudioinfo->nrates; i++) | | 631 | for (i = 0; i < tmpaudioinfo->nrates; i++) |
628 | tmpaudioinfo->rates[i] = tmpinfo.play.sample_rate; | | 632 | tmpaudioinfo->rates[i] = tmpinfo.play.sample_rate; |
629 | tmpaudioinfo->min_channels = tmpinfo.play.channels; | | 633 | tmpaudioinfo->min_channels = tmpinfo.play.channels; |
630 | tmpaudioinfo->max_channels = tmpinfo.play.channels; | | 634 | tmpaudioinfo->max_channels = tmpinfo.play.channels; |
631 | tmpaudioinfo->binding = -1; | | 635 | tmpaudioinfo->binding = -1; |
632 | tmpaudioinfo->rate_source = -1; | | 636 | tmpaudioinfo->rate_source = -1; |
633 | memset(tmpaudioinfo->handle, 0, 16); | | 637 | memset(tmpaudioinfo->handle, 0, 16); |
634 | tmpaudioinfo->next_play_engine = 0; | | 638 | tmpaudioinfo->next_play_engine = 0; |
635 | tmpaudioinfo->next_rec_engine = 0; | | 639 | tmpaudioinfo->next_rec_engine = 0; |
636 | argp = tmpaudioinfo; | | 640 | argp = tmpaudioinfo; |
637 | break; | | 641 | break; |
638 | case SNDCTL_DSP_GETPLAYVOL: | | | |
639 | retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); | | | |
640 | if (retval < 0) | | | |
641 | return retval; | | | |
642 | *(uint *)argp = tmpinfo.play.gain; | | | |
643 | break; | | | |
644 | case SNDCTL_DSP_SETPLAYVOL: | | 642 | case SNDCTL_DSP_SETPLAYVOL: |
645 | retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); | | 643 | setvol(fd, INTARG, false); |
646 | if (retval < 0) | | 644 | /* FALLTHRU */ |
647 | return retval; | | 645 | case SNDCTL_DSP_GETPLAYVOL: |
648 | if (*(uint *)argp > 255) | | 646 | retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo); |
649 | tmpinfo.play.gain = 255; | | | |
650 | else | | | |
651 | tmpinfo.play.gain = *(uint *)argp; | | | |
652 | retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo); | | | |
653 | if (retval < 0) | | | |
654 | return retval; | | | |
655 | break; | | | |
656 | case SNDCTL_DSP_GETRECVOL: | | | |
657 | retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); | | | |
658 | if (retval < 0) | | 647 | if (retval < 0) |
659 | return retval; | | 648 | return retval; |
660 | *(uint *)argp = tmpinfo.record.gain; | | 649 | INTARG = getvol(tmpinfo.play.gain, tmpinfo.play.balance); |
661 | break; | | 650 | break; |
662 | case SNDCTL_DSP_SETRECVOL: | | 651 | case SNDCTL_DSP_SETRECVOL: |
663 | retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); | | 652 | setvol(fd, INTARG, true); |
664 | if (retval < 0) | | 653 | /* FALLTHRU */ |
665 | return retval; | | 654 | case SNDCTL_DSP_GETRECVOL: |
666 | if (*(uint *)argp > 255) | | 655 | retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo); |
667 | tmpinfo.record.gain = 255; | | | |
668 | else | | | |
669 | tmpinfo.record.gain = *(uint *)argp; | | | |
670 | retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo); | | | |
671 | if (retval < 0) | | 656 | if (retval < 0) |
672 | return retval; | | 657 | return retval; |
| | | 658 | INTARG = getvol(tmpinfo.record.gain, tmpinfo.record.balance); |
673 | break; | | 659 | break; |
674 | case SNDCTL_DSP_SKIP: | | 660 | case SNDCTL_DSP_SKIP: |
675 | case SNDCTL_DSP_SILENCE: | | 661 | case SNDCTL_DSP_SILENCE: |
676 | return EINVAL; | | 662 | return EINVAL; |
677 | case SNDCTL_DSP_SETDUPLEX: | | 663 | case SNDCTL_DSP_SETDUPLEX: |
678 | idat = 1; | | 664 | idat = 1; |
679 | retval = ioctl(fd, AUDIO_SETFD, &idat); | | 665 | retval = ioctl(fd, AUDIO_SETFD, &idat); |
680 | if (retval < 0) | | 666 | if (retval < 0) |
681 | return retval; | | 667 | return retval; |
682 | break; | | 668 | break; |
683 | case SNDCTL_DSP_GETODELAY: | | 669 | case SNDCTL_DSP_GETODELAY: |
684 | retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); | | 670 | retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); |
685 | if (retval < 0) | | 671 | if (retval < 0) |
| @@ -1037,26 +1023,73 @@ mixer_ioctl(int fd, unsigned long com, v | | | @@ -1037,26 +1023,73 @@ mixer_ioctl(int fd, unsigned long com, v |
1037 | if (MIXER_WRITE(SOUND_MIXER_FIRST) <= com && | | 1023 | if (MIXER_WRITE(SOUND_MIXER_FIRST) <= com && |
1038 | com < MIXER_WRITE(SOUND_MIXER_NRDEVICES)) | | 1024 | com < MIXER_WRITE(SOUND_MIXER_NRDEVICES)) |
1039 | return 0; | | 1025 | return 0; |
1040 | goto doread; | | 1026 | goto doread; |
1041 | } else { | | 1027 | } else { |
1042 | errno = EINVAL; | | 1028 | errno = EINVAL; |
1043 | return -1; | | 1029 | return -1; |
1044 | } | | 1030 | } |
1045 | } | | 1031 | } |
1046 | INTARG = (int)idat; | | 1032 | INTARG = (int)idat; |
1047 | return 0; | | 1033 | return 0; |
1048 | } | | 1034 | } |
1049 | | | 1035 | |
| | | 1036 | static int |
| | | 1037 | getvol(u_int gain, u_char balance) |
| | | 1038 | { |
| | | 1039 | u_int l, r; |
| | | 1040 | |
| | | 1041 | if (balance == AUDIO_MID_BALANCE) { |
| | | 1042 | l = r = gain; |
| | | 1043 | } else if (balance < AUDIO_MID_BALANCE) { |
| | | 1044 | l = gain; |
| | | 1045 | r = (balance * gain) / AUDIO_MID_BALANCE; |
| | | 1046 | } else { |
| | | 1047 | r = gain; |
| | | 1048 | l = ((AUDIO_RIGHT_BALANCE - balance) * gain) |
| | | 1049 | / AUDIO_MID_BALANCE; |
| | | 1050 | } |
| | | 1051 | |
| | | 1052 | return TO_OSSVOL(l) | (TO_OSSVOL(r) << 8); |
| | | 1053 | } |
| | | 1054 | |
| | | 1055 | static void |
| | | 1056 | setvol(int fd, int volume, bool record) |
| | | 1057 | { |
| | | 1058 | u_int lgain, rgain; |
| | | 1059 | struct audio_info tmpinfo; |
| | | 1060 | struct audio_prinfo *prinfo; |
| | | 1061 | |
| | | 1062 | AUDIO_INITINFO(&tmpinfo); |
| | | 1063 | prinfo = record ? &tmpinfo.record : &tmpinfo.play; |
| | | 1064 | |
| | | 1065 | lgain = FROM_OSSVOL((volume >> 0) & 0xff); |
| | | 1066 | rgain = FROM_OSSVOL((volume >> 8) & 0xff); |
| | | 1067 | |
| | | 1068 | if (lgain == rgain) { |
| | | 1069 | prinfo->gain = lgain; |
| | | 1070 | prinfo->balance = AUDIO_MID_BALANCE; |
| | | 1071 | } else if (lgain < rgain) { |
| | | 1072 | prinfo->gain = rgain; |
| | | 1073 | prinfo->balance = AUDIO_RIGHT_BALANCE - |
| | | 1074 | (AUDIO_MID_BALANCE * lgain) / rgain; |
| | | 1075 | } else { |
| | | 1076 | prinfo->gain = lgain; |
| | | 1077 | prinfo->balance = (AUDIO_MID_BALANCE * rgain) / lgain; |
| | | 1078 | } |
| | | 1079 | |
| | | 1080 | (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo); |
| | | 1081 | } |
| | | 1082 | |
1050 | /* | | 1083 | /* |
1051 | * When AUDIO_SETINFO fails to set a channel count, the application's chosen | | 1084 | * When AUDIO_SETINFO fails to set a channel count, the application's chosen |
1052 | * number is out of range of what the kernel allows. | | 1085 | * number is out of range of what the kernel allows. |
1053 | * | | 1086 | * |
1054 | * When this happens, we use the current hardware settings. This is just in | | 1087 | * When this happens, we use the current hardware settings. This is just in |
1055 | * case an application is abusing SNDCTL_DSP_CHANNELS - OSSv4 always sets and | | 1088 | * case an application is abusing SNDCTL_DSP_CHANNELS - OSSv4 always sets and |
1056 | * returns a reasonable value, even if it wasn't what the user requested. | | 1089 | * returns a reasonable value, even if it wasn't what the user requested. |
1057 | * | | 1090 | * |
1058 | * XXX: If a device is opened for both playback and recording, and supports | | 1091 | * XXX: If a device is opened for both playback and recording, and supports |
1059 | * fewer channels for recording than playback, applications that do both will | | 1092 | * fewer channels for recording than playback, applications that do both will |
1060 | * behave very strangely. OSS doesn't allow for reporting separate channel | | 1093 | * behave very strangely. OSS doesn't allow for reporting separate channel |
1061 | * counts for recording and playback. This could be worked around by always | | 1094 | * counts for recording and playback. This could be worked around by always |
1062 | * mixing recorded data up to the same number of channels as is being used | | 1095 | * mixing recorded data up to the same number of channels as is being used |