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 /*
24  * These are largely device specific operations for the audio devices. Some of
25  * the calls are general, but may eventually be used by several of the SLab
26  * applications.
27  *
28  * The operations for audio control are rather ugly. The application sets up
29  * a number of values in the controlBuffer, and the engine intermittanly looks
30  * to see if these values are initialised. If so, it acts on the values, and
31  * then clears them. The reason we have to use this indirection is that the
32  * front end applications do not own the audio device, this is under control
33  * of the engine.
34  *
35  *	Jul 28th 96 - Only LINUX code is active.
36  */
37 
38 /*
39  * Audio device structure format definitions.
40  */
41 #include "slabrevisions.h"
42 #include "slabaudiodev.h"
43 #include "slabcdefs.h"
44 #include "bristol.h"
45 
46 #if (BRISTOL_HAS_ALSA == 1)
47 #include "slabalsadev.h"
48 #endif
49 
50 extern int ossAudioInit(duplexDev *, int, int);
51 extern int alsaDevOpen(duplexDev *, int, int, int);
52 extern int alsaDevClose(duplexDev *);
53 extern int alsaDevAudioStart(duplexDev *);
54 
55 #ifdef DEBUG
56 #include <stdio.h>
57 #endif
58 #include <unistd.h>
59 #include <fcntl.h>
60 #ifdef SUBFRAGMENT
61 #include <stdlib.h>
62 #ifndef __FreeBSD__
63 #include <malloc.h>
64 #endif
65 #endif
66 
67 #include <sys/ioctl.h>
68 
69 #if (BRISTOL_HAS_OSS == 1)
70 /*
71  * This may want to be /usr/lib/oss/include/sys/soundcard.h if someone has
72  * purchased the 4Front drivers?
73  */
74 #include <sys/soundcard.h>
75 audio_buf_info bufferInfo;
76 #endif
77 
78 /*
79 static char *SLAB_SND_LABELS[SLAB_NRDEVICES] =	SLAB_DEVICE_LABELS;
80  * Called once when the device is opened by the engine. Initialises our fd to
81  * 44100 16 bits stereo operation.
82  * Changed for 2.30 (or so) to include capability to have no requests to alter
83  * the default fragment size. The code will do a simplified audio init, and let\ * the audio IO daemon use the default fragment for IO, decoupled from the block
84  * sample size.
85  */
86 int
initAudioDevice2(audioDev,devID,fragSize)87 initAudioDevice2(audioDev, devID, fragSize)
88 duplexDev *audioDev;
89 int devID;
90 {
91 	/*
92 	 * The device is basically just opened for the first call of this routine.
93 	 * This is then called several times afterwards - each time we start the
94 	 * engine (that is a tape start, not an engine restart). This may be
95 	 * problematic.
96 	 *
97 	 * First set duplex (later check duplex).
98 	 * Set the fragments.
99 	 * In this order set bits, channels, speed.
100 	 */
101 #ifdef BRISTOL_PA
102 	if (audioDev->siflags & AUDIO_PULSE)
103 		return(0);
104 #endif
105 #if (BRISTOL_HAS_ALSA == 1)
106 	/*
107 	 * ALSA is one of the secondary intrusive flags. If this is set we have
108 	 * already configured what we want from the open request on the device.
109 	 */
110 	if (audioDev->siflags & AUDIO_ALSA)
111 		return(0);
112 #endif
113 
114 	/*
115 	 * If we get here we need to call some OSS routine.
116 	 */
117 	return(ossAudioInit(audioDev, devID, fragSize));
118 }
119 
120 int
setAudioStart2(audioDev,devID)121 setAudioStart2(audioDev, devID)
122 duplexDev *audioDev;
123 {
124 	int enable;
125 
126 #ifdef IOCTL_DBG
127 	if (audioDev->cflags & SLAB_AUDIODBG)
128 		printf("setAudioStart2(%i)\n", devID);
129 #endif
130 
131 	if (audioDev->flags & AUDIO_DUMMY)
132 		return(0);
133 
134 #ifdef BRISTOL_PA
135 	if (audioDev->siflags & AUDIO_PULSE)
136 		return(0);
137 #endif
138 #if (BRISTOL_HAS_ALSA == 1)
139 	if (audioDev->siflags & AUDIO_ALSA)
140 	{
141 		alsaDevAudioStart(audioDev);
142 		return(0);
143 	}
144 #endif
145 	if (audioDev->fd < 0)
146 		return(0);
147 
148 #if (BRISTOL_HAS_OSS == 1)
149 	if ((audioDev->genCaps & SNDCTL_DSP_SETTRIGGER) &&
150 		(audioDev->Command == 1))
151 	{
152 		enable = (PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT);
153 #ifdef IOCTL_DBG
154 		if (audioDev->cflags & SLAB_AUDIODBG)
155 			printf("ioctl(%i, SNDCTL_DSP_SETTRIGGER, &%08x)\n",
156 				audioDev->fd, enable);
157 #endif
158 		ioctl(audioDev->fd, SNDCTL_DSP_SETTRIGGER, &enable);
159 	}
160 #endif
161 	return(0);
162 }
163 
164 int
setAudioStop2(audioDev,devID)165 setAudioStop2(audioDev, devID)
166 duplexDev *audioDev;
167 {
168 	int enable;
169 
170 #ifdef IOCTL_DBG
171 	if (audioDev->cflags & SLAB_AUDIODBG)
172 		printf("setAudioStop2(%i)\n", devID);
173 #endif
174 
175 	if (audioDev->siflags & AUDIO_DUMMY)
176 		return(0);
177 
178 #ifdef BRISTOL_PA
179 	if (audioDev->siflags & AUDIO_PULSE)
180 		return(0);
181 #endif
182 #if (BRISTOL_HAS_ALSA == 1)
183 	if (audioDev->siflags & AUDIO_ALSA)
184 	{
185 #ifdef IOCTL_DBG
186 		/*
187 		 * This is a superfluous bit of debug, but it will at least show that
188 		 * we are recognising the ALSA configuration status. There are no audio
189 		 * stop commands associated with the SLab ALSA drivers, although we
190 		 * could use the "pause" calls.
191 		 */
192 		if (audioDev->cflags & SLAB_AUDIODBG)
193 			printf("ALSA device, returning from setAudioStop2\n");
194 #endif
195 		return(0);
196 	}
197 #endif
198 
199 	if (audioDev->fd < 0)
200 		return(0);
201 
202 #if (BRISTOL_HAS_OSS == 1)
203 	if ((audioDev->genCaps & SNDCTL_DSP_SETTRIGGER) &&
204 		(audioDev->Command == 1))
205 	{
206 		enable = ~(PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT);
207 #ifdef IOCTL_DBG
208 		if (audioDev->cflags & SLAB_AUDIODBG)
209 			printf("ioctl(%i, SNDCTL_DSP_SETTRIGGER, &%08x)\n",
210 				audioDev->fd, enable);
211 #endif
212 		ioctl(audioDev->fd, SNDCTL_DSP_SETTRIGGER, &enable);
213 #ifdef IOCTL_DBG
214 		if (audioDev->cflags & SLAB_AUDIODBG)
215 		{
216 			ioctl(audioDev->fd, SNDCTL_DSP_GETTRIGGER, &enable);
217 			printf("ioctl(%i, SNDCTL_DSP_GETTRIGGER, &%08x)\n",
218 				audioDev->fd, enable);
219 		}
220 #endif
221 	}
222 #endif
223 
224 	return(0);
225 }
226 
227 int
audioClose(duplexDev * audioDev)228 audioClose(duplexDev *audioDev)
229 {
230 	if (audioDev->cflags & SLAB_AUDIODBG)
231 		printf("audioClose(%p, %i, %s)\n", audioDev, audioDev->devID,
232 			audioDev->devName);
233 
234 	if (audioDev->flags & AUDIO_DUMMY) {
235 		printf("closing AUDIO_DUMMY interface\n");
236 		return(0);
237 	}
238 
239 #ifdef BRISTOL_PA
240 	if (audioDev->siflags & AUDIO_PULSE)
241 	{
242 		pulseDevClose(audioDev);
243 		return(0);
244 	}
245 #endif
246 
247 #if (BRISTOL_HAS_ALSA == 1)
248 	if (audioDev->siflags & AUDIO_ALSA)
249 	{
250 		alsaDevClose(audioDev);
251 		return(0);
252 	}
253 #endif
254 
255 	if (audioDev->fd != -1)
256 	{
257 		close(audioDev->fd);
258 		audioDev->fd = -1;
259 	}
260 	if (audioDev->fd2 != -1)
261 	{
262 		close(audioDev->fd2);
263 		audioDev->fd2 = -1;
264 	}
265 
266 	bristolfree(audioDev->fragBuf);
267 	audioDev->fragBuf = NULL;
268 
269 	return(0);
270 }
271 
272 int
audioOpen(duplexDev * audioDev,int device,int flags)273 audioOpen(duplexDev *audioDev, int device, int flags)
274 {
275 	if (audioDev->cflags & SLAB_AUDIODBG)
276 		printf("audioOpen(%p, %i, %i): %s\n", audioDev, device, flags,
277 			audioDev->devName);
278 
279 	if (audioDev->flags & AUDIO_DUMMY) {
280 		printf("using AUDIO_DUMMY interface\n");
281 
282 		if (audioDev->fragBuf)
283 			bristolfree(audioDev->fragBuf);
284 
285 		if (audioDev->channels == 0)
286 			audioDev->channels = 2;
287 
288 		if (audioDev->fragSize == 0)
289 			audioDev->fragSize = 1024;
290 
291 		if (audioDev->writeSampleRate == 0)
292 			audioDev->writeSampleRate = 44100;
293 		if (audioDev->readSampleRate == 0)
294 			audioDev->readSampleRate = 44100;
295 
296 		audioDev->fragBuf = (char *) bristolmalloc(audioDev->fragSize);
297 
298 		return(10);
299 	}
300 
301 #ifdef BRISTOL_PA
302 	if (audioDev->siflags & AUDIO_PULSE)
303 		return(pulseDevOpen(audioDev, device, flags, audioDev->fragSize));
304 #endif
305 #if (BRISTOL_HAS_ALSA == 1)
306 	if ((audioDev->siflags & AUDIO_ALSA) && (audioDev->devName[0] != '/'))
307 		return(alsaDevOpen(audioDev, device, flags, audioDev->fragSize));
308 #endif
309 	/*
310 	 * We need to "mung" the flags.
311 	 */
312 	if (flags == SLAB_OWRONLY)
313 		flags = O_WRONLY;
314 	else if (flags == SLAB_ORDONLY)
315 		flags = O_RDONLY;
316 	else if (flags == SLAB_ORDWR)
317 		flags = O_RDWR;
318 	else {
319 		printf("	WHAT WERE THOSE FLAGS: %x\n", flags);
320 		/*
321 		 * We may as well take some default value if we are unsure about the
322 		 * request.
323 		 */
324 		flags = O_RDWR;
325 	}
326 	if (audioDev->cflags & SLAB_AUDIODBG)
327 		printf("flags are now %i\n", flags);
328 	/*
329 	 * Open the device.
330 	 */
331 	if ((audioDev->fd = open(audioDev->devName, flags)) < 0)
332 	{
333 		/*
334 		 * Device open failed. Print an error message and exit.
335 		 */
336 		printf("Failed to open audio device \"%s\", flags %i\n",
337 			audioDev->devName, flags);
338 		return(-10);
339 #ifdef IOCTL_DBG
340 		if (audioDev->cflags & SLAB_AUDIODBG)
341 			printf("Opened audio device \"%s\"\n", audioDev->devName);
342 #endif
343 	}
344 
345 	/*
346 	 * We will eventually allow configurable buffer sizes. At the moment we
347 	 * will take the default value for the main output device, and
348 	 * configure that on all the other devices.
349 	 */
350 	if (audioDev->fragSize == 0)
351 		audioDev->fragSize = 1024;
352 	audioDev->flags = flags;
353 
354 	bristolfree(audioDev->fragBuf);
355 
356 	audioDev->fragBuf = (char *) bristolmalloc(audioDev->fragSize);
357 
358 	initAudioDevice2(audioDev, device, audioDev->fragSize);
359 
360 	/*
361 	audioDev->flags |= SLAB_AUDIODBG2;
362 	audioDev->cflags |= SLAB_AUDIODBG;
363 	*/
364 
365 	return(audioDev->fd);
366 }
367 
368 int
channelStatus(duplexDev * audioDev)369 channelStatus(duplexDev *audioDev)
370 {
371 	return(0);
372 }
373 
374 int
headStatus(duplexDev * audioDev)375 headStatus(duplexDev *audioDev)
376 {
377 	return(0);
378 }
379 
380