xref: /plan9/sys/src/cmd/unix/drawterm/kern/devaudio-unix.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
1 /*
2  * Linux and BSD
3  */
4 #include <sys/ioctl.h>
5 #ifdef __linux__
6 #include <linux/soundcard.h>
7 #else
8 #include <sys/soundcard.h>
9 #endif
10 #include	"u.h"
11 #include	"lib.h"
12 #include	"dat.h"
13 #include	"fns.h"
14 #include	"error.h"
15 #include	"devaudio.h"
16 
17 enum
18 {
19 	Channels = 2,
20 	Rate = 44100,
21 	Bits = 16,
22 	Bigendian = 1,
23 };
24 
25 static int afd = -1;
26 static int cfd= -1;
27 static int speed;
28 
29 /* maybe this should return -1 instead of sysfatal */
30 void
audiodevopen(void)31 audiodevopen(void)
32 {
33 	int t;
34 	ulong ul;
35 
36 	afd = -1;
37 	cfd = -1;
38 	if((afd = open("/dev/dsp", OWRITE)) < 0)
39 		goto err;
40 	if((cfd = open("/dev/mixer", ORDWR)) < 0)
41 		goto err;
42 
43 	t = Bits;
44 	if(ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &t) < 0)
45 		goto err;
46 
47 	t = Channels-1;
48 	if(ioctl(afd, SNDCTL_DSP_STEREO, &t) < 0)
49 		goto err;
50 
51 	speed = Rate;
52 	ul = Rate;
53 	if(ioctl(afd, SNDCTL_DSP_SPEED, &ul) < 0)
54 		goto err;
55 
56 	return;
57 
58 err:
59 	if(afd >= 0)
60 		close(afd);
61 	afd = -1;
62 	oserror();
63 }
64 
65 void
audiodevclose(void)66 audiodevclose(void)
67 {
68 	close(afd);
69 	close(cfd);
70 	afd = -1;
71 	cfd = -1;
72 }
73 
74 static struct {
75 	int id9;
76 	int id;
77 } names[] = {
78 	Vaudio,	SOUND_MIXER_VOLUME,
79 	Vbass, 		SOUND_MIXER_BASS,
80 	Vtreb, 		SOUND_MIXER_TREBLE,
81 	Vline, 		SOUND_MIXER_LINE,
82 	Vpcm, 		SOUND_MIXER_PCM,
83 	Vsynth, 		SOUND_MIXER_SYNTH,
84 	Vcd, 		SOUND_MIXER_CD,
85 	Vmic, 		SOUND_MIXER_MIC,
86 //	"record", 		SOUND_MIXER_RECLEV,
87 //	"mix",		SOUND_MIXER_IMIX,
88 //	"pcm2",		SOUND_MIXER_ALTPCM,
89 	Vspeaker,	SOUND_MIXER_SPEAKER
90 //	"line1",		SOUND_MIXER_LINE1,
91 //	"line2",		SOUND_MIXER_LINE2,
92 //	"line3",		SOUND_MIXER_LINE3,
93 //	"digital1",	SOUND_MIXER_DIGITAL1,
94 //	"digital2",	SOUND_MIXER_DIGITAL2,
95 //	"digital3",	SOUND_MIXER_DIGITAL3,
96 //	"phonein",		SOUND_MIXER_PHONEIN,
97 //	"phoneout",		SOUND_MIXER_PHONEOUT,
98 //	"radio",		SOUND_MIXER_RADIO,
99 //	"video",		SOUND_MIXER_VIDEO,
100 //	"monitor",	SOUND_MIXER_MONITOR,
101 //	"igain",		SOUND_MIXER_IGAIN,
102 //	"ogain",		SOUND_MIXER_OGAIN,
103 };
104 
105 static int
lookname(int id9)106 lookname(int id9)
107 {
108 	int i;
109 
110 	for(i=0; i<nelem(names); i++)
111 		if(names[i].id9 == id9)
112 			return names[i].id;
113 	return -1;
114 }
115 
116 void
audiodevsetvol(int what,int left,int right)117 audiodevsetvol(int what, int left, int right)
118 {
119 	int id;
120 	ulong x;
121 	int can, v;
122 
123 	if(cfd < 0)
124 		error("audio device not open");
125 	if(what == Vspeed){
126 		x = left;
127 		if(ioctl(afd, SNDCTL_DSP_SPEED, &x) < 0)
128 			oserror();
129 		speed = x;
130 		return;
131 	}
132 	if((id = lookname(what)) < 0)
133 		return;
134 	if(ioctl(cfd, SOUND_MIXER_READ_DEVMASK, &can) < 0)
135 		can = ~0;
136 	if(!(can & (1<<id)))
137 		return;
138 	v = left | (right<<8);
139 	if(ioctl(cfd, MIXER_WRITE(id), &v) < 0)
140 		oserror();
141 }
142 
143 void
audiodevgetvol(int what,int * left,int * right)144 audiodevgetvol(int what, int *left, int *right)
145 {
146 	int id;
147 	int can, v;
148 
149 	if(cfd < 0)
150 		error("audio device not open");
151 	if(what == Vspeed){
152 		*left = *right = speed;
153 		return;
154 	}
155 	if((id = lookname(what)) < 0)
156 		return;
157 	if(ioctl(cfd, SOUND_MIXER_READ_DEVMASK, &can) < 0)
158 		can = ~0;
159 	if(!(can & (1<<id)))
160 		return;
161 	if(ioctl(cfd, MIXER_READ(id), &v) < 0)
162 		oserror();
163 	*left = v&0xFF;
164 	*right = (v>>8)&0xFF;
165 }
166 
167 int
audiodevwrite(void * v,int n)168 audiodevwrite(void *v, int n)
169 {
170 	int m, tot;
171 
172 	for(tot=0; tot<n; tot+=m)
173 		if((m = write(afd, (uchar*)v+tot, n-tot)) <= 0)
174 			oserror();
175 	return tot;
176 }
177 
178 int
audiodevread(void * v,int n)179 audiodevread(void *v, int n)
180 {
181 	error("no reading");
182 	return -1;
183 }
184