diff options
author | Wincent Balin <wincent@rockbox.org> | 2010-06-03 00:39:13 +0000 |
---|---|---|
committer | Wincent Balin <wincent@rockbox.org> | 2010-06-03 00:39:13 +0000 |
commit | c1ae4414d4ac6504992434b949b252c30daf0c48 (patch) | |
tree | 696c5781e9a00cea694117eb3ef404d37f10930e /apps/plugins/pdbox/PDa/src/s_audio_oss.c | |
parent | 5edd8cf736232a240e2f4f47eb847e1901d18379 (diff) | |
download | rockbox-c1ae4414d4ac6504992434b949b252c30daf0c48.tar.gz rockbox-c1ae4414d4ac6504992434b949b252c30daf0c48.zip |
pdbox: Source cleanup. Removed unneeded files.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26497 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/s_audio_oss.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/s_audio_oss.c | 845 |
1 files changed, 0 insertions, 845 deletions
diff --git a/apps/plugins/pdbox/PDa/src/s_audio_oss.c b/apps/plugins/pdbox/PDa/src/s_audio_oss.c deleted file mode 100644 index de11f66243..0000000000 --- a/apps/plugins/pdbox/PDa/src/s_audio_oss.c +++ /dev/null | |||
@@ -1,845 +0,0 @@ | |||
1 | /* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler, | ||
2 | * Winfried Ritsch, Karl MacMillan, and others. | ||
3 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
4 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
5 | |||
6 | /* this file inputs and outputs audio using the OSS API available on linux. */ | ||
7 | |||
8 | #ifdef USEAPI_OSS | ||
9 | |||
10 | #include <linux/soundcard.h> | ||
11 | |||
12 | #include "m_pd.h" | ||
13 | #include "s_stuff.h" | ||
14 | #include <errno.h> | ||
15 | #include <stdio.h> | ||
16 | #include <unistd.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <string.h> | ||
19 | #include <sys/types.h> | ||
20 | #include <sys/time.h> | ||
21 | #include <sys/stat.h> | ||
22 | #include <sys/ioctl.h> | ||
23 | #include <fcntl.h> | ||
24 | #include <sched.h> | ||
25 | #include <sys/mman.h> | ||
26 | |||
27 | |||
28 | /* Defines */ | ||
29 | #define DEBUG(x) x | ||
30 | #define DEBUG2(x) {x;} | ||
31 | |||
32 | #define OSS_MAXCHPERDEV 32 /* max channels per OSS device */ | ||
33 | #define OSS_MAXDEV 4 /* maximum number of input or output devices */ | ||
34 | #define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */ | ||
35 | #define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */ | ||
36 | #define OSS_DEFAULTCH 2 | ||
37 | #define RME_DEFAULTCH 8 /* need this even if RME undefined */ | ||
38 | typedef int16_t t_oss_int16; | ||
39 | typedef int32_t t_oss_int32; | ||
40 | #define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32) | ||
41 | #define OSS_BYTESPERCHAN(width) (DEFDACBLKSIZE * (width)) | ||
42 | #define OSS_XFERSAMPS(chans) (DEFDACBLKSIZE* (chans)) | ||
43 | #define OSS_XFERSIZE(chans, width) (DEFDACBLKSIZE * (chans) * (width)) | ||
44 | |||
45 | /* GLOBALS */ | ||
46 | static int linux_meters; /* true if we're metering */ | ||
47 | static float linux_inmax; /* max input amplitude */ | ||
48 | static float linux_outmax; /* max output amplitude */ | ||
49 | static int linux_fragsize = 0; /* for block mode; block size (sample frames) */ | ||
50 | |||
51 | /* our device handles */ | ||
52 | |||
53 | typedef struct _oss_dev | ||
54 | { | ||
55 | int d_fd; | ||
56 | unsigned int d_space; /* bytes available for writing/reading */ | ||
57 | int d_bufsize; /* total buffer size in blocks for this device */ | ||
58 | int d_dropcount; /* # of buffers to drop for resync (output only) */ | ||
59 | unsigned int d_nchannels; /* number of channels for this device */ | ||
60 | unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */ | ||
61 | } t_oss_dev; | ||
62 | |||
63 | static t_oss_dev linux_dacs[OSS_MAXDEV]; | ||
64 | static t_oss_dev linux_adcs[OSS_MAXDEV]; | ||
65 | static int linux_noutdevs = 0; | ||
66 | static int linux_nindevs = 0; | ||
67 | |||
68 | /* exported variables */ | ||
69 | float sys_dacsr; | ||
70 | t_sample *sys_soundout; | ||
71 | t_sample *sys_soundin; | ||
72 | |||
73 | /* OSS-specific private variables */ | ||
74 | static int oss_blockmode = 1; /* flag to use "blockmode" */ | ||
75 | static int oss_32bit = 0; /* allow 23 bit transfers in OSS */ | ||
76 | static char ossdsp[] = "/dev/dsp%d"; | ||
77 | |||
78 | /* don't assume we can turn all 31 bits when doing float-to-fix; | ||
79 | otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */ | ||
80 | #define FMAX 0x7ffff000 | ||
81 | #define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x)) | ||
82 | |||
83 | |||
84 | /* ------------- private routines for all APIS ------------------- */ | ||
85 | |||
86 | static void linux_flush_all_underflows_to_zero(void) | ||
87 | { | ||
88 | /* | ||
89 | TODO: Implement similar thing for linux (GGeiger) | ||
90 | |||
91 | One day we will figure this out, I hope, because it | ||
92 | costs CPU time dearly on Intel - LT | ||
93 | */ | ||
94 | /* union fpc_csr f; | ||
95 | f.fc_word = get_fpc_csr(); | ||
96 | f.fc_struct.flush = 1; | ||
97 | set_fpc_csr(f.fc_word); | ||
98 | */ | ||
99 | } | ||
100 | |||
101 | static int oss_ndev = 0; | ||
102 | |||
103 | /* find out how many OSS devices we have. Since this has to | ||
104 | open the devices to find out if they're there, we have | ||
105 | to be called before audio is actually started up. So we | ||
106 | cache the results, which in effect are the number of available | ||
107 | devices. */ | ||
108 | void oss_init(void) | ||
109 | { | ||
110 | int fd, i; | ||
111 | static int countedthem = 0; | ||
112 | if (countedthem) | ||
113 | return; | ||
114 | for (i = 0; i < 10; i++) | ||
115 | { | ||
116 | char devname[100]; | ||
117 | if (i == 0) | ||
118 | strcpy(devname, "/dev/dsp"); | ||
119 | else sprintf(devname, "/dev/dsp%d", i); | ||
120 | if ( (fd = open(devname, O_WRONLY|O_NONBLOCK)) != -1) | ||
121 | { | ||
122 | oss_ndev++; | ||
123 | close(fd); | ||
124 | } | ||
125 | else break; | ||
126 | } | ||
127 | countedthem = 1; | ||
128 | } | ||
129 | |||
130 | |||
131 | void oss_set32bit( void) | ||
132 | { | ||
133 | oss_32bit = 1; | ||
134 | } | ||
135 | |||
136 | |||
137 | typedef struct _multidev { | ||
138 | int fd; | ||
139 | int channels; | ||
140 | int format; | ||
141 | } t_multidev; | ||
142 | |||
143 | int oss_reset(int fd) { | ||
144 | int err; | ||
145 | if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0) | ||
146 | error("OSS: Could not reset"); | ||
147 | return err; | ||
148 | } | ||
149 | |||
150 | /* The AFMT_S32_BLOCKED format is not defined in standard linux kernels | ||
151 | but is proposed by Guenter Geiger to support extending OSS to handle | ||
152 | 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall. | ||
153 | I'm not clear why this isn't called AFMT_S32_[SLN]E... */ | ||
154 | |||
155 | #ifndef AFMT_S32_BLOCKED | ||
156 | #define AFMT_S32_BLOCKED 0x0000400 | ||
157 | #endif | ||
158 | |||
159 | void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize) | ||
160 | { /* IOhannes */ | ||
161 | int orig, param, nblk, fd = dev->d_fd, wantformat; | ||
162 | int nchannels = dev->d_nchannels; | ||
163 | int advwas = sys_schedadvance; | ||
164 | |||
165 | audio_buf_info ainfo; | ||
166 | |||
167 | /* IOhannes : | ||
168 | * pd is very likely to crash if different formats are used on | ||
169 | multiple soundcards | ||
170 | */ | ||
171 | |||
172 | /* set resolution - first try 4 byte samples */ | ||
173 | if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,¶m) >= 0) && | ||
174 | (param & AFMT_S32_BLOCKED)) | ||
175 | { | ||
176 | wantformat = AFMT_S32_BLOCKED; | ||
177 | dev->d_bytespersamp = 4; | ||
178 | } | ||
179 | else | ||
180 | { | ||
181 | wantformat = AFMT_S16_NE; | ||
182 | dev->d_bytespersamp = 2; | ||
183 | } | ||
184 | param = wantformat; | ||
185 | |||
186 | if (sys_verbose) | ||
187 | post("bytes per sample = %d", dev->d_bytespersamp); | ||
188 | if (ioctl(fd, SNDCTL_DSP_SETFMT, ¶m) == -1) | ||
189 | fprintf(stderr,"OSS: Could not set DSP format\n"); | ||
190 | else if (wantformat != param) | ||
191 | fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n", | ||
192 | wantformat, param); | ||
193 | |||
194 | /* sample rate */ | ||
195 | orig = param = srate; | ||
196 | if (ioctl(fd, SNDCTL_DSP_SPEED, ¶m) == -1) | ||
197 | fprintf(stderr,"OSS: Could not set sampling rate for device\n"); | ||
198 | else if( orig != param ) | ||
199 | fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n", | ||
200 | orig, param ); | ||
201 | |||
202 | if (oss_blockmode && !skipblocksize) | ||
203 | { | ||
204 | int fragbytes, logfragsize, nfragment; | ||
205 | /* setting fragment count and size. */ | ||
206 | if (!linux_fragsize) | ||
207 | { | ||
208 | linux_fragsize = OSS_DEFFRAGSIZE; | ||
209 | while (linux_fragsize > DEFDACBLKSIZE | ||
210 | && linux_fragsize * 4 > sys_advance_samples) | ||
211 | linux_fragsize = linux_fragsize/2; | ||
212 | } | ||
213 | |||
214 | /* post("adv_samples %d", sys_advance_samples); */ | ||
215 | nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize; | ||
216 | |||
217 | fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels); | ||
218 | logfragsize = ilog2(fragbytes); | ||
219 | |||
220 | if (fragbytes != (1 << logfragsize)) | ||
221 | post("warning: OSS takes only power of 2 blocksize; using %d", | ||
222 | (1 << logfragsize)/(dev->d_bytespersamp * nchannels)); | ||
223 | if (sys_verbose) | ||
224 | post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes); | ||
225 | |||
226 | param = orig = (nfragment<<16) + logfragsize; | ||
227 | if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, ¶m) == -1) | ||
228 | error("OSS: Could not set or read fragment size\n"); | ||
229 | if (param != orig) | ||
230 | { | ||
231 | nfragment = ((param >> 16) & 0xffff); | ||
232 | logfragsize = (param & 0xffff); | ||
233 | post("warning: actual fragments %d, blocksize %d", | ||
234 | nfragment, (1 << logfragsize)); | ||
235 | } | ||
236 | if (sys_verbose) | ||
237 | post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance)); | ||
238 | } | ||
239 | if (dac) | ||
240 | { | ||
241 | /* use "free space" to learn the buffer size. Normally you | ||
242 | should set this to your own desired value; but this seems not | ||
243 | to be implemented uniformly across different sound cards. LATER | ||
244 | we should figure out what to do if the requested scheduler advance | ||
245 | is greater than this buffer size; for now, we just print something | ||
246 | out. */ | ||
247 | |||
248 | int defect; | ||
249 | if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0) | ||
250 | fprintf(stderr,"OSS: ioctl on output device failed"); | ||
251 | dev->d_bufsize = ainfo.bytes; | ||
252 | |||
253 | defect = sys_advance_samples * (dev->d_bytespersamp * nchannels) | ||
254 | - dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp); | ||
255 | if (defect > 0) | ||
256 | { | ||
257 | if (sys_verbose || defect > (dev->d_bufsize >> 2)) | ||
258 | fprintf(stderr, | ||
259 | "OSS: requested audio buffer size %d limited to %d\n", | ||
260 | sys_advance_samples * (dev->d_bytespersamp * nchannels), | ||
261 | dev->d_bufsize); | ||
262 | sys_advance_samples = | ||
263 | (dev->d_bufsize - OSS_XFERSAMPS(nchannels)) / | ||
264 | (dev->d_bytespersamp *nchannels); | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | |||
269 | static int oss_setchannels(int fd, int wantchannels, char *devname) | ||
270 | { /* IOhannes */ | ||
271 | int param = wantchannels; | ||
272 | |||
273 | while (param>1) { | ||
274 | int save = param; | ||
275 | if (ioctl(fd, SNDCTL_DSP_CHANNELS, ¶m) == -1) { | ||
276 | error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname); | ||
277 | } else { | ||
278 | if (param == save) return (param); | ||
279 | } | ||
280 | param=save-1; | ||
281 | } | ||
282 | |||
283 | return (0); | ||
284 | } | ||
285 | |||
286 | #define O_AUDIOFLAG 0 /* O_NDELAY */ | ||
287 | |||
288 | int oss_open_audio(int nindev, int *indev, int nchin, int *chin, | ||
289 | int noutdev, int *outdev, int nchout, int *chout, int rate) | ||
290 | { /* IOhannes */ | ||
291 | int capabilities = 0; | ||
292 | int inchannels = 0, outchannels = 0; | ||
293 | char devname[20]; | ||
294 | int n, i, fd; | ||
295 | char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV]; | ||
296 | int num_devs = 0; | ||
297 | int wantmore=0; | ||
298 | int spread = 0; | ||
299 | audio_buf_info ainfo; | ||
300 | |||
301 | linux_nindevs = linux_noutdevs = 0; | ||
302 | |||
303 | |||
304 | /* mark input devices unopened */ | ||
305 | for (i = 0; i < OSS_MAXDEV; i++) | ||
306 | linux_adcs[i].d_fd = -1; | ||
307 | |||
308 | /* open output devices */ | ||
309 | wantmore=0; | ||
310 | if (noutdev < 0 || nindev < 0) | ||
311 | bug("linux_open_audio"); | ||
312 | |||
313 | for (n = 0; n < noutdev; n++) | ||
314 | { | ||
315 | int gotchans, j, inindex = -1; | ||
316 | int thisdevice = (outdev[n] >= 0 ? outdev[n] : n-1); | ||
317 | int wantchannels = (nchout>n) ? chout[n] : wantmore; | ||
318 | fd = -1; | ||
319 | if (!wantchannels) | ||
320 | goto end_out_loop; | ||
321 | |||
322 | if (thisdevice > 1) | ||
323 | sprintf(devname, "/dev/dsp%d", thisdevice-1); | ||
324 | else sprintf(devname, "/dev/dsp"); | ||
325 | |||
326 | /* search for input request for same device. Succeed only | ||
327 | if the number of channels matches. */ | ||
328 | for (j = 0; j < nindev; j++) | ||
329 | if (indev[j] == thisdevice && chin[j] == wantchannels) | ||
330 | inindex = j; | ||
331 | |||
332 | /* if the same device is requested for input and output, | ||
333 | try to open it read/write */ | ||
334 | if (inindex >= 0) | ||
335 | { | ||
336 | sys_setalarm(1000000); | ||
337 | if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1) | ||
338 | { | ||
339 | post("%s (read/write): %s", devname, strerror(errno)); | ||
340 | post("(now will try write-only...)"); | ||
341 | } | ||
342 | else | ||
343 | { | ||
344 | if (sys_verbose) | ||
345 | post("opened %s for reading and writing\n", devname); | ||
346 | linux_adcs[inindex].d_fd = fd; | ||
347 | } | ||
348 | } | ||
349 | /* if that didn't happen or if it failed, try write-only */ | ||
350 | if (fd == -1) | ||
351 | { | ||
352 | sys_setalarm(1000000); | ||
353 | if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1) | ||
354 | { | ||
355 | post("%s (writeonly): %s", | ||
356 | devname, strerror(errno)); | ||
357 | break; | ||
358 | } | ||
359 | if (sys_verbose) | ||
360 | post("opened %s for writing only\n", devname); | ||
361 | } | ||
362 | if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1) | ||
363 | error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname); | ||
364 | |||
365 | gotchans = oss_setchannels(fd, | ||
366 | (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, | ||
367 | devname); | ||
368 | |||
369 | if (sys_verbose) | ||
370 | post("opened audio output on %s; got %d channels", | ||
371 | devname, gotchans); | ||
372 | |||
373 | if (gotchans < 2) | ||
374 | { | ||
375 | /* can't even do stereo? just give up. */ | ||
376 | close(fd); | ||
377 | } | ||
378 | else | ||
379 | { | ||
380 | linux_dacs[linux_noutdevs].d_nchannels = gotchans; | ||
381 | linux_dacs[linux_noutdevs].d_fd = fd; | ||
382 | oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0); | ||
383 | |||
384 | linux_noutdevs++; | ||
385 | outchannels += gotchans; | ||
386 | if (inindex >= 0) | ||
387 | { | ||
388 | linux_adcs[inindex].d_nchannels = gotchans; | ||
389 | chin[inindex] = gotchans; | ||
390 | } | ||
391 | } | ||
392 | /* LATER think about spreading large numbers of channels over | ||
393 | various dsp's and vice-versa */ | ||
394 | wantmore = wantchannels - gotchans; | ||
395 | end_out_loop: ; | ||
396 | } | ||
397 | |||
398 | /* open input devices */ | ||
399 | wantmore = 0; | ||
400 | for (n = 0; n < nindev; n++) | ||
401 | { | ||
402 | int gotchans=0; | ||
403 | int thisdevice = (indev[n] >= 0 ? indev[n] : n-1); | ||
404 | int wantchannels = (nchin>n)?chin[n]:wantmore; | ||
405 | int alreadyopened = 0; | ||
406 | if (!wantchannels) | ||
407 | goto end_in_loop; | ||
408 | |||
409 | if (thisdevice > 1) | ||
410 | sprintf(devname, "/dev/dsp%d", thisdevice - 1); | ||
411 | else sprintf(devname, "/dev/dsp"); | ||
412 | |||
413 | sys_setalarm(1000000); | ||
414 | |||
415 | /* perhaps it's already open from the above? */ | ||
416 | if (linux_dacs[n].d_fd >= 0) | ||
417 | { | ||
418 | fd = linux_dacs[n].d_fd; | ||
419 | alreadyopened = 1; | ||
420 | } | ||
421 | else | ||
422 | { | ||
423 | /* otherwise try to open it here. */ | ||
424 | if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1) | ||
425 | { | ||
426 | post("%s (readonly): %s", devname, strerror(errno)); | ||
427 | goto end_in_loop; | ||
428 | } | ||
429 | if (sys_verbose) | ||
430 | post("opened %s for reading only\n", devname); | ||
431 | } | ||
432 | linux_adcs[linux_nindevs].d_fd = fd; | ||
433 | gotchans = oss_setchannels(fd, | ||
434 | (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels, | ||
435 | devname); | ||
436 | if (sys_verbose) | ||
437 | post("opened audio input device %s; got %d channels", | ||
438 | devname, gotchans); | ||
439 | |||
440 | if (gotchans < 1) | ||
441 | { | ||
442 | close(fd); | ||
443 | goto end_in_loop; | ||
444 | } | ||
445 | |||
446 | linux_adcs[linux_nindevs].d_nchannels = gotchans; | ||
447 | |||
448 | oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened); | ||
449 | |||
450 | inchannels += gotchans; | ||
451 | linux_nindevs++; | ||
452 | |||
453 | wantmore = wantchannels-gotchans; | ||
454 | /* LATER think about spreading large numbers of channels over | ||
455 | various dsp's and vice-versa */ | ||
456 | end_in_loop: ; | ||
457 | } | ||
458 | |||
459 | /* We have to do a read to start the engine. This is | ||
460 | necessary because sys_send_dacs waits until the input | ||
461 | buffer is filled and only reads on a filled buffer. | ||
462 | This is good, because it's a way to make sure that we | ||
463 | will not block. But I wonder why we only have to read | ||
464 | from one of the devices and not all of them??? */ | ||
465 | |||
466 | if (linux_nindevs) | ||
467 | { | ||
468 | if (sys_verbose) | ||
469 | fprintf(stderr,("OSS: issuing first ADC 'read' ... ")); | ||
470 | read(linux_adcs[0].d_fd, buf, | ||
471 | linux_adcs[0].d_bytespersamp * | ||
472 | linux_adcs[0].d_nchannels * DEFDACBLKSIZE); | ||
473 | if (sys_verbose) | ||
474 | fprintf(stderr, "...done.\n"); | ||
475 | } | ||
476 | sys_setalarm(0); | ||
477 | return (0); | ||
478 | } | ||
479 | |||
480 | void oss_close_audio( void) | ||
481 | { | ||
482 | int i; | ||
483 | for (i=0;i<linux_nindevs;i++) | ||
484 | close(linux_adcs[i].d_fd); | ||
485 | |||
486 | for (i=0;i<linux_noutdevs;i++) | ||
487 | close(linux_dacs[i].d_fd); | ||
488 | |||
489 | linux_nindevs = linux_noutdevs = 0; | ||
490 | } | ||
491 | |||
492 | static int linux_dacs_write(int fd,void* buf,long bytes) | ||
493 | { | ||
494 | return write(fd, buf, bytes); | ||
495 | } | ||
496 | |||
497 | static int linux_adcs_read(int fd,void* buf,long bytes) | ||
498 | { | ||
499 | return read(fd, buf, bytes); | ||
500 | } | ||
501 | |||
502 | /* query audio devices for "available" data size. */ | ||
503 | static void oss_calcspace(void) | ||
504 | { | ||
505 | int dev; | ||
506 | audio_buf_info ainfo; | ||
507 | for (dev=0; dev < linux_noutdevs; dev++) | ||
508 | { | ||
509 | if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0) | ||
510 | fprintf(stderr,"OSS: ioctl on output device %d failed",dev); | ||
511 | linux_dacs[dev].d_space = ainfo.bytes; | ||
512 | } | ||
513 | |||
514 | for (dev = 0; dev < linux_nindevs; dev++) | ||
515 | { | ||
516 | if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0) | ||
517 | fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed", | ||
518 | dev, linux_adcs[dev].d_fd); | ||
519 | linux_adcs[dev].d_space = ainfo.bytes; | ||
520 | } | ||
521 | } | ||
522 | |||
523 | void linux_audiostatus(void) | ||
524 | { | ||
525 | int dev; | ||
526 | if (!oss_blockmode) | ||
527 | { | ||
528 | oss_calcspace(); | ||
529 | for (dev=0; dev < linux_noutdevs; dev++) | ||
530 | fprintf(stderr, "dac %d space %d\n", dev, linux_dacs[dev].d_space); | ||
531 | |||
532 | for (dev = 0; dev < linux_nindevs; dev++) | ||
533 | fprintf(stderr, "adc %d space %d\n", dev, linux_adcs[dev].d_space); | ||
534 | |||
535 | } | ||
536 | } | ||
537 | |||
538 | /* this call resyncs audio output and input which will cause discontinuities | ||
539 | in audio output and/or input. */ | ||
540 | |||
541 | static void oss_doresync( void) | ||
542 | { | ||
543 | int dev, zeroed = 0, wantsize; | ||
544 | char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV]; | ||
545 | audio_buf_info ainfo; | ||
546 | |||
547 | /* 1. if any input devices are ahead (have more than 1 buffer stored), | ||
548 | drop one or more buffers worth */ | ||
549 | for (dev = 0; dev < linux_nindevs; dev++) | ||
550 | { | ||
551 | if (linux_adcs[dev].d_space == 0) | ||
552 | { | ||
553 | linux_adcs_read(linux_adcs[dev].d_fd, buf, | ||
554 | OSS_XFERSIZE(linux_adcs[dev].d_nchannels, | ||
555 | linux_adcs[dev].d_bytespersamp)); | ||
556 | } | ||
557 | else while (linux_adcs[dev].d_space > | ||
558 | OSS_XFERSIZE(linux_adcs[dev].d_nchannels, | ||
559 | linux_adcs[dev].d_bytespersamp)) | ||
560 | { | ||
561 | linux_adcs_read(linux_adcs[dev].d_fd, buf, | ||
562 | OSS_XFERSIZE(linux_adcs[dev].d_nchannels, | ||
563 | linux_adcs[dev].d_bytespersamp)); | ||
564 | if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0) | ||
565 | { | ||
566 | fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed", | ||
567 | dev, linux_adcs[dev].d_fd); | ||
568 | break; | ||
569 | } | ||
570 | linux_adcs[dev].d_space = ainfo.bytes; | ||
571 | } | ||
572 | } | ||
573 | |||
574 | /* 2. if any output devices are behind, feed them zeros to catch them | ||
575 | up */ | ||
576 | for (dev = 0; dev < linux_noutdevs; dev++) | ||
577 | { | ||
578 | while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize - | ||
579 | sys_advance_samples * (linux_dacs[dev].d_nchannels * | ||
580 | linux_dacs[dev].d_bytespersamp)) | ||
581 | { | ||
582 | if (!zeroed) | ||
583 | { | ||
584 | unsigned int i; | ||
585 | for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels); | ||
586 | i++) | ||
587 | buf[i] = 0; | ||
588 | zeroed = 1; | ||
589 | } | ||
590 | linux_dacs_write(linux_dacs[dev].d_fd, buf, | ||
591 | OSS_XFERSIZE(linux_dacs[dev].d_nchannels, | ||
592 | linux_dacs[dev].d_bytespersamp)); | ||
593 | if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0) | ||
594 | { | ||
595 | fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed", | ||
596 | dev, linux_dacs[dev].d_fd); | ||
597 | break; | ||
598 | } | ||
599 | linux_dacs[dev].d_space = ainfo.bytes; | ||
600 | } | ||
601 | } | ||
602 | /* 3. if any DAC devices are too far ahead, plan to drop the | ||
603 | number of frames which will let the others catch up. */ | ||
604 | for (dev = 0; dev < linux_noutdevs; dev++) | ||
605 | { | ||
606 | if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize - | ||
607 | (sys_advance_samples - 1) * linux_dacs[dev].d_nchannels * | ||
608 | linux_dacs[dev].d_bytespersamp) | ||
609 | { | ||
610 | linux_dacs[dev].d_dropcount = sys_advance_samples - 1 - | ||
611 | (linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) / | ||
612 | (linux_dacs[dev].d_nchannels * | ||
613 | linux_dacs[dev].d_bytespersamp) ; | ||
614 | } | ||
615 | else linux_dacs[dev].d_dropcount = 0; | ||
616 | } | ||
617 | } | ||
618 | |||
619 | int oss_send_dacs(void) | ||
620 | { | ||
621 | t_sample *fp1, *fp2; | ||
622 | long fill; | ||
623 | int i, j, dev, rtnval = SENDDACS_YES; | ||
624 | char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV]; | ||
625 | t_oss_int16 *sp; | ||
626 | t_oss_int32 *lp; | ||
627 | /* the maximum number of samples we should have in the ADC buffer */ | ||
628 | int idle = 0; | ||
629 | int thischan; | ||
630 | t_time timeref, timenow; | ||
631 | |||
632 | if (!linux_nindevs && !linux_noutdevs) | ||
633 | return (SENDDACS_NO); | ||
634 | |||
635 | if (!oss_blockmode) | ||
636 | { | ||
637 | /* determine whether we're idle. This is true if either (1) | ||
638 | some input device has less than one buffer to read or (2) some | ||
639 | output device has fewer than (sys_advance_samples) blocks buffered | ||
640 | already. */ | ||
641 | oss_calcspace(); | ||
642 | |||
643 | for (dev=0; dev < linux_noutdevs; dev++) | ||
644 | if (linux_dacs[dev].d_dropcount || | ||
645 | (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space > | ||
646 | sys_advance_samples * linux_dacs[dev].d_bytespersamp * | ||
647 | linux_dacs[dev].d_nchannels)) | ||
648 | idle = 1; | ||
649 | for (dev=0; dev < linux_nindevs; dev++) | ||
650 | if (linux_adcs[dev].d_space < | ||
651 | OSS_XFERSIZE(linux_adcs[dev].d_nchannels, | ||
652 | linux_adcs[dev].d_bytespersamp)) | ||
653 | idle = 1; | ||
654 | } | ||
655 | |||
656 | if (idle && !oss_blockmode) | ||
657 | { | ||
658 | /* sometimes---rarely---when the ADC available-byte-count is | ||
659 | zero, it's genuine, but usually it's because we're so | ||
660 | late that the ADC has overrun its entire kernel buffer. We | ||
661 | distinguish between the two by waiting 2 msec and asking again. | ||
662 | There should be an error flag we could check instead; look for this | ||
663 | someday... */ | ||
664 | for (dev = 0;dev < linux_nindevs; dev++) | ||
665 | if (linux_adcs[dev].d_space == 0) | ||
666 | { | ||
667 | audio_buf_info ainfo; | ||
668 | sys_microsleep(2000); | ||
669 | oss_calcspace(); | ||
670 | if (linux_adcs[dev].d_space != 0) continue; | ||
671 | |||
672 | /* here's the bad case. Give up and resync. */ | ||
673 | sys_log_error(ERR_DATALATE); | ||
674 | oss_doresync(); | ||
675 | return (SENDDACS_NO); | ||
676 | } | ||
677 | /* check for slippage between devices, either because | ||
678 | data got lost in the driver from a previous late condition, or | ||
679 | because the devices aren't synced. When we're idle, no | ||
680 | input device should have more than one buffer readable and | ||
681 | no output device should have less than sys_advance_samples-1 | ||
682 | */ | ||
683 | |||
684 | for (dev=0; dev < linux_noutdevs; dev++) | ||
685 | if (!linux_dacs[dev].d_dropcount && | ||
686 | (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space < | ||
687 | (sys_advance_samples - 2) * | ||
688 | (linux_dacs[dev].d_bytespersamp * | ||
689 | linux_dacs[dev].d_nchannels))) | ||
690 | goto badsync; | ||
691 | for (dev=0; dev < linux_nindevs; dev++) | ||
692 | if (linux_adcs[dev].d_space > 3 * | ||
693 | OSS_XFERSIZE(linux_adcs[dev].d_nchannels, | ||
694 | linux_adcs[dev].d_bytespersamp)) | ||
695 | goto badsync; | ||
696 | |||
697 | /* return zero to tell the scheduler we're idle. */ | ||
698 | return (SENDDACS_NO); | ||
699 | badsync: | ||
700 | sys_log_error(ERR_RESYNC); | ||
701 | oss_doresync(); | ||
702 | return (SENDDACS_NO); | ||
703 | |||
704 | } | ||
705 | |||
706 | |||
707 | /* do output */ | ||
708 | |||
709 | timeref = sys_getrealtime(); | ||
710 | for (dev=0, thischan = 0; dev < linux_noutdevs; dev++) | ||
711 | { | ||
712 | int nchannels = linux_dacs[dev].d_nchannels; | ||
713 | if (linux_dacs[dev].d_dropcount) | ||
714 | linux_dacs[dev].d_dropcount--; | ||
715 | else | ||
716 | { | ||
717 | if (linux_dacs[dev].d_bytespersamp == 4) | ||
718 | { | ||
719 | for (i = DEFDACBLKSIZE * nchannels, fp1 = sys_soundout + | ||
720 | DEFDACBLKSIZE*thischan, | ||
721 | lp = (t_oss_int32 *)buf; i--; fp1++, lp++) | ||
722 | { | ||
723 | t_sample f = SCALE32(*fp1); | ||
724 | *lp = (f >= 2147483647 ? 2147483647 : | ||
725 | (f < -2147483647 ? -2147483647 : f)); | ||
726 | } | ||
727 | } | ||
728 | else | ||
729 | { | ||
730 | for (i = DEFDACBLKSIZE, fp1 = sys_soundout + | ||
731 | DEFDACBLKSIZE*thischan, | ||
732 | sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels) | ||
733 | { | ||
734 | for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += DEFDACBLKSIZE) | ||
735 | { | ||
736 | int s = SCALE16(*fp2); | ||
737 | if (s > 32767) s = 32767; | ||
738 | else if (s < -32767) s = -32767; | ||
739 | sp[j] = s; | ||
740 | } | ||
741 | } | ||
742 | } | ||
743 | |||
744 | |||
745 | #if 0 | ||
746 | #define PR_S "%8d" | ||
747 | { | ||
748 | int nm = 64; | ||
749 | int* sp1 = buf; | ||
750 | post("dac:"); | ||
751 | while (nm > 0) | ||
752 | { | ||
753 | post(PR_S PR_S PR_S PR_S PR_S PR_S PR_S PR_S, | ||
754 | sp1[0], sp1[1], sp1[2], sp1[3], sp1[4], sp1[5], sp1[6], sp1[7]); | ||
755 | nm -= 8; | ||
756 | sp1 += 8; | ||
757 | } | ||
758 | } | ||
759 | #endif | ||
760 | linux_dacs_write(linux_dacs[dev].d_fd, buf, | ||
761 | OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp)); | ||
762 | |||
763 | #if 0 | ||
764 | if ((timenow = sys_getrealtime()) - timeref > 200) | ||
765 | { | ||
766 | post("dacslept %d",sys_getrealtime() - timeref); | ||
767 | if (!oss_blockmode) | ||
768 | sys_log_error(ERR_DACSLEPT); | ||
769 | else rtnval = SENDDACS_SLEPT; | ||
770 | } | ||
771 | #endif | ||
772 | timeref = timenow; | ||
773 | } | ||
774 | thischan += nchannels; | ||
775 | } | ||
776 | memset(sys_soundout, 0, | ||
777 | sys_outchannels * (sizeof(float) * DEFDACBLKSIZE)); | ||
778 | |||
779 | /* do input */ | ||
780 | |||
781 | for (dev = 0, thischan = 0; dev < linux_nindevs; dev++) | ||
782 | { | ||
783 | int nchannels = linux_adcs[dev].d_nchannels; | ||
784 | linux_adcs_read(linux_adcs[dev].d_fd, buf, | ||
785 | OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp)); | ||
786 | |||
787 | #if 0 | ||
788 | if ((timenow = sys_getrealtime()) - timeref > 200) | ||
789 | { | ||
790 | if (!oss_blockmode) | ||
791 | sys_log_error(ERR_ADCSLEPT); | ||
792 | else | ||
793 | rtnval = SENDDACS_SLEPT; | ||
794 | } | ||
795 | #endif | ||
796 | timeref = timenow; | ||
797 | |||
798 | if (linux_adcs[dev].d_bytespersamp == 4) | ||
799 | { | ||
800 | for (i = DEFDACBLKSIZE*nchannels, | ||
801 | fp1 = sys_soundin + thischan*DEFDACBLKSIZE, | ||
802 | lp = (t_oss_int32 *)buf; i--; fp1++, lp++) | ||
803 | { | ||
804 | *fp1 = ((t_sample)(*lp))*(t_sample)(1./2147483648.); | ||
805 | } | ||
806 | } | ||
807 | else | ||
808 | { | ||
809 | for (i = DEFDACBLKSIZE,fp1 = sys_soundin + thischan*DEFDACBLKSIZE, | ||
810 | sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels) | ||
811 | { | ||
812 | for (j=0;j<sys_inchannels;j++) | ||
813 | fp1[j*DEFDACBLKSIZE] = INVSCALE16(sp[j]); | ||
814 | } | ||
815 | } | ||
816 | thischan += nchannels; | ||
817 | } | ||
818 | if (thischan != sys_inchannels) | ||
819 | bug("inchannels"); | ||
820 | return (rtnval); | ||
821 | } | ||
822 | |||
823 | void oss_listdevs( void) | ||
824 | { | ||
825 | post("device listing not implemented in OSS yet\n"); | ||
826 | } | ||
827 | |||
828 | void oss_getdevs(char *indevlist, int *nindevs, | ||
829 | char *outdevlist, int *noutdevs, int *canmulti, | ||
830 | int maxndev, int devdescsize) | ||
831 | { | ||
832 | int i, ndev; | ||
833 | *canmulti = 2; /* supports multiple devices */ | ||
834 | if ((ndev = oss_ndev) > maxndev) | ||
835 | ndev = maxndev; | ||
836 | for (i = 0; i < ndev; i++) | ||
837 | { | ||
838 | sprintf(indevlist + i * devdescsize, "OSS device #%d", i+1); | ||
839 | sprintf(outdevlist + i * devdescsize, "OSS device #%d", i+1); | ||
840 | } | ||
841 | *nindevs = *noutdevs = ndev; | ||
842 | } | ||
843 | |||
844 | #endif | ||
845 | |||