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