1 
2 /*
3  *  Diverse SLab audio routines.
4  *  Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5  *
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 3 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 
23 #if (BRISTOL_HAS_OSS == 1)
24 /*
25  * This may want to be /usr/lib/oss/include/sys/soundcard.h if someone has
26  * purchased the 4Front drivers?
27  */
28 #include <sys/soundcard.h>
29 #endif
30 
31 #include <sys/ioctl.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <strings.h>
37 
38 /*
39  * Audio device structure format definitions.
40  */
41 #include "slabrevisions.h"
42 #include "slabaudiodev.h"
43 #include "bristol.h"
44 
45 int newInitAudioDevice2(duplexDev *, int, int);
46 static void checkAudioCaps2(duplexDev *, int, int);
47 
48 int
ossAudioInit(audioDev,devID,fragSize)49 ossAudioInit(audioDev, devID, fragSize)
50 duplexDev *audioDev;
51 int devID;
52 {
53 #if (BRISTOL_HAS_OSS == 1)
54 	int results, data = 0, mode;
55 
56 	//audioDev->cflags |= SLAB_AUDIODBG;
57 
58 	printf("ossAudioInit(%p, %i, %i)\n", audioDev, devID, fragSize);
59 
60 	/*
61 	 * This is what we are going to go for.
62 	 */
63 	fragSize = 1024;
64 
65 	/*
66 	 * Clear out this buffer.
67 	 */
68 	if (audioDev->fragBuf != (char *) NULL)
69 	{
70 		bristolfree(audioDev->fragBuf);
71 		audioDev->fragBuf = (char *) NULL;
72 	}
73 
74 	checkAudioCaps2(audioDev, devID, audioDev->fd);
75 
76 	if (fragSize != 0)
77 	{
78 		int data;
79 
80 		switch(fragSize) {
81 			case 1024:
82 				data = 0x0040000a;
83 				break;
84 			case 2048:
85 				data = 0x0020000b;
86 				break;
87 			case 4096:
88 				data = 0x0010000c;
89 				break;
90 			case 8192:
91 				data = 0x0008000d;
92 				break;
93 			case 16384:
94 				data = 0x0004000e;
95 				break;
96 			/*
97 			 * This is 8192 blockSampleSize, where internally we deal with
98 			 * ints or floats, but the IO buffer is in shorts.
99 			 */
100 			case 32768:
101 			default:
102 				data = 0x0004000f;
103 				break;
104 		}
105 		if ((results = ioctl(audioDev->fd, SNDCTL_DSP_SETFRAGMENT, &data)) == 0)
106 		{
107 			if (audioDev->cflags & SLAB_AUDIODBG)
108 				printf("ioctl(%i, SNDCTL_DSP_SETFRAGMENT, %x)\n",
109 					audioDev->fd, data);
110 		} else
111 			printf("ioctl(%i, SNDCTL_DSP_SETFRAGMENT, %x): failed\n",
112 				audioDev->fd, data);
113 	}
114 
115 	/*
116 	 * Check capabilities.
117 	 */
118 	if (audioDev->cflags & SLAB_AUDIODBG)
119 		printf("ioctl(%i, SNDCTL_DSP_GETCAPS, &0x%x)\n", audioDev->fd, data);
120 
121 	if ((results = ioctl(audioDev->fd, SNDCTL_DSP_GETCAPS, &data)) == 0)
122 	{
123 		audioDev->genCaps = data;
124 
125 		if (audioDev->cflags & SLAB_AUDIODBG)
126 		{
127 			if ((audioDev->genCaps & SNDCTL_DSP_SETTRIGGER) != 0)
128 				printf("Device %s does support SNDCTL_SET_TRIGGER\n",
129 					audioDev->devName);
130 			else
131 				printf("Device %s does NOT support SNDCTL_SET_TRIGGER\n",
132 					audioDev->devName);
133 		}
134 
135 		/*
136 		 * Take this out, we only need to check the options here.
137 		 */
138 		if (data & DSP_CAP_DUPLEX)
139 		{
140 
141 			if (audioDev->cflags & SLAB_AUDIODBG)
142 				printf("ioctl(%i, SNDCTL_DSP_SETDUPLEX, &0x%x)\n",
143 					audioDev->fd, data);
144 
145 			if (ioctl(audioDev->fd, SNDCTL_DSP_SETDUPLEX, &data) < 0)
146 				printf("Failed to set Duplex\n");
147 			else
148 				printf("Set to Duplex\n");
149 		}
150 	}
151 
152 	if ((audioDev->cflags & SLAB_FDUP) == 0)
153 		audioDev->fd2 = audioDev->fd;
154 	else
155 		audioDev->fd2 = fcntl(audioDev->fd, F_DUPFD, audioDev->fd);
156 
157 	/*
158 	 * Set to required resolution.
159 	 */
160 	if (audioDev->cflags & (SLAB_8_BIT_OUT|SLAB_8_BIT_IN))
161 	{
162 		data = 8; /* THIS SHOULD USE THE soundcard.h DEFINITION */
163 	} else
164 		data = 16;
165 
166 	if (audioDev->cflags & SLAB_AUDIODBG)
167 		printf("ioctl(%i, SNDCTL_DSP_SETFMT, &%i)\n", audioDev->fd, data);
168 
169 	if ((results = ioctl(audioDev->fd, SNDCTL_DSP_SETFMT, &data)) == 0)
170 	{
171 		if (audioDev->cflags & SLAB_AUDIODBG)
172 			printf("Set audio format: %i\n", data);
173 	} else
174 		printf("Set resolution failed: %i\n", results);
175 
176 	/*
177 	 * Set to stereo
178 	 */
179 	data = 1;
180 	if (audioDev->cflags & SLAB_AUDIODBG)
181 		printf("ioctl(%i, SNDCTL_DSP_STEREO, &%i)\n", audioDev->fd, data);
182 	mode = SNDCTL_DSP_STEREO;
183 	if ((results = ioctl(audioDev->fd, mode, &data)) == 0)
184 	{
185 		if (audioDev->cflags & SLAB_AUDIODBG)
186 			printf("Set to stereo: %i\n", data);
187 	} else
188 		printf("Set stereo failed: %i\n", results);
189 
190 	/*
191 	 * Set to AUDIO_RATE Hz
192 	 */
193 	data = audioDev->writeSampleRate;
194 
195 	if (audioDev->cflags & SLAB_AUDIODBG)
196 		printf("ioctl(%i, SNDCTL_DSP_SPEED, &%i)\n", audioDev->fd, data);
197 
198 	if ((results = ioctl(audioDev->fd, SNDCTL_DSP_SPEED, &data)) == 0)
199 	{
200 		if (audioDev->cflags & SLAB_AUDIODBG)
201 			printf("Set audio readwrite rate to %i\n", data);
202 	} else
203 		printf("Set line frequency failed: %i\n", results);
204 
205 	/*
206 	 * Save the actual physical line rate for conversions later
207 	 */
208 	audioDev->writeSampleRate = data;
209 
210 	/*
211 	 * Save the actual physical line rate for conversions later
212 	 */
213 	audioDev->readSampleRate = data;
214 
215 	/*
216 	 * Finally get the output fragment size. We can have an awkward problem if
217 	 * this fragment size is not the same as the primary device - with sync IO
218 	 * where we readBuffer/writeBuffer, having different sizes very soon puts
219 	 * the audio daemon in to a lock state. To overcome this, and to support
220 	 * eventual realtime mixing (where we will specify a small buffersize
221 	 * anyway) we should add a "desired buffer size" param, or have the adiod
222 	 * routines cater for differences.
223 	 */
224 	data = 0;
225 	if ((results = ioctl(audioDev->fd, SNDCTL_DSP_GETBLKSIZE, &data)) == 0)
226 	{
227 		audioDev->fragSize = data;
228 
229 		if (audioDev->cflags & SLAB_AUDIODBG)
230 			printf("ioctl(%i, SNDCTL_DSP_GETBLKSIZE, &0): %i bytes\n",
231 				audioDev->fd, audioDev->fragSize);
232 		audioDev->fragBuf = (char *) bristolmalloc(audioDev->fragSize);
233 	}
234 	else
235 		printf("Get frag size failed: %i\n", results);
236 
237 #ifdef _BRISTOL_DRAIN
238 	for (data = 0; data < audioDev->preLoad; data++)
239 		results = write(audioDev->fd, audioDev->fragBuf,
240 			audioDev->samplecount * 2 * audioDev->channels);
241 #endif
242 
243 #endif /* BRISTOL_HAS_OSS */
244 
245 	return(0);
246 }
247 
248 /*
249  * Needs to be ALSAfied - ie, binned if we have alsa - this is GUI stuff.
250  */
251 static void
checkAudioCaps2(audioDev,devID,fd)252 checkAudioCaps2(audioDev, devID, fd)
253 duplexDev *audioDev;
254 int devID, fd;
255 {
256 	int i, stereodevs = 0;
257 
258 #if (BRISTOL_HAS_OSS == 1)
259 	printf("checkAudioCaps2(%i, %i)\n", devID, fd);
260 
261     if (ioctl(fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs) == -1)
262 	{
263 		if (audioDev->cflags & SLAB_AUDIODBG)
264 			printf("Failed to get stereo capabilities: %08x\n", stereodevs);
265 	} else {
266 		if (audioDev->cflags & SLAB_AUDIODBG)
267 			printf("Capabilities: %08x\n", stereodevs);
268 		audioDev->stereoCaps = stereodevs;
269 	}
270 
271 
272 	for (i = 1; i < 131072; i = i << 1) {
273 		if (i & stereodevs)
274 			printf("Found stereo dev %08x\n", i);
275 	}
276 
277 	stereodevs = 0;
278     if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &stereodevs) == -1)
279 	{
280 		if (audioDev->cflags & SLAB_AUDIODBG)
281 			printf("Failed to get audio capabilities: %08x\n", stereodevs);
282 	} else {
283 		if (audioDev->cflags & SLAB_AUDIODBG)
284 			printf("Mono Capabilities: %08x\n", stereodevs);
285 		audioDev->monoCaps = stereodevs;
286 	}
287 
288 
289 	stereodevs = 0;
290     if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &stereodevs) == -1)
291 	{
292 		if (audioDev->cflags & SLAB_AUDIODBG)
293 			printf("Failed to get record capabilities: %08x\n", stereodevs);
294 	} else {
295 		if (audioDev->cflags & SLAB_AUDIODBG)
296 			printf("Record Caps: %08x\n", stereodevs);
297 		audioDev->recordCaps = stereodevs;
298 	}
299 
300 #endif /* BRISTOL_HAS_OSS */
301 }
302 
303