~ubuntu-branches/ubuntu/precise/puredata/precise

« back to all changes in this revision

Viewing changes to .pc/audio_oss_cleanup.patch/src/s_audio_oss.c

  • Committer: Bazaar Package Importer
  • Author(s): Paul Brossier, IOhannes m zmölnig, Paul Brossier
  • Date: 2011-05-11 01:03:01 UTC
  • Revision ID: james.westby@ubuntu.com-20110511010301-fem05b1q975xx0gz
Tags: 0.43.0-3
[ IOhannes m zmölnig ]
* debian/patches/kfreebsd_fixes.patch: kFreeBSD build fixes
* debian/rules: simplified arch-dependent build-depends
* debian/rules: use dh_auto_configure, distinguish between linux/non-linux
* debian/patches/audio_oss_cleanup.patch: cleanup ifdef logic in
  s_audio_oss.c
* debian/patches/hurd_fixes.patch: fix hurd compilation
* debian/patches/series: updated
* debian/rules: link with --as-needed
* debian/patches/clean_helpbrowser.patch: cleanup helpbrowser to show files
  after directories
* forwarded patches to upstream
* debian/changelog: shortened changelog-lines to keep lintian happy
* debian/control: Conflict with older versions of puredata (Closes: #625663)

[ Paul Brossier ]
* debian/changelog: write changelog, build and upload package.

Show diffs side-by-side

added added

removed removed

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