root/rat/trunk/auddev_luigi.c @ 2314

Revision 2314, 12.9 KB (checked in by ucaccsp, 15 years ago)

Major copyright update....
- All files are now under a standard Berkeley-style copyright notice
- Version number bumped to 4.0.0

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * FILE:    auddev_luigi.c - Sound interface for Luigi Rizzo's FreeBSD driver
3 *
4 * $Revision$
5 * $Date$
6 *
7 * Copyright (c) 1996-98 University College London
8 * All rights reserved.
9 *
10 */
11
12#ifdef FreeBSD
13
14#include "config_unix.h"
15#include "config_win32.h"
16#include "audio_types.h"
17#include "audio_fmt.h"
18#include "auddev_luigi.h"
19#include "memory.h"
20#include "debug.h"
21
22#define LUIGI_SPEAKER    0x101
23#define LUIGI_MICROPHONE 0x201
24#define LUIGI_LINE_IN    0x202
25#define LUIGI_CD         0x203
26
27static int iport = LUIGI_MICROPHONE;
28static snd_chan_param pa;
29static struct snd_size sz;
30
31static int audio_fd = -1;
32
33
34#define RAT_TO_DEVICE(x) ((x) * 100 / MAX_AMP)
35#define DEVICE_TO_RAT(x) ((x) * MAX_AMP / 100)
36
37#define LUIGI_AUDIO_IOCTL(fd, cmd, val) if (ioctl((fd), (cmd), (val)) < 0) { \
38                                            debug_msg("Failed %s\n",#cmd); \
39                                            luigi_error = __LINE__; \
40                                               }
41
42#define LUIGI_MAX_AUDIO_NAME_LEN 32
43#define LUIGI_MAX_AUDIO_DEVICES  3
44
45static int dev_ids[LUIGI_MAX_AUDIO_DEVICES];
46static char names[LUIGI_MAX_AUDIO_DEVICES][LUIGI_MAX_AUDIO_NAME_LEN];
47static int ndev = 0;
48static int luigi_error;
49
50int 
51luigi_audio_open(audio_desc_t ad, audio_format *ifmt, audio_format *ofmt)
52{
53        int             volume = 100;
54        int             reclb = 0;
55       
56        char            thedev[64];
57       
58        assert(ad >= 0 && ad < ndev);
59        sprintf(thedev, "/dev/audio%d", dev_ids[ad]);
60
61        audio_fd = open(thedev, O_RDWR);
62        if (audio_fd >= 0) {
63                snd_capabilities soundcaps;
64                /* Ignore any earlier errors */
65                luigi_error = 0;
66
67                LUIGI_AUDIO_IOCTL(audio_fd, AIOGCAP, &soundcaps);
68                LUIGI_AUDIO_IOCTL(audio_fd,SNDCTL_DSP_RESET,0);
69
70                switch (soundcaps.formats & (AFMT_FULLDUPLEX | AFMT_WEIRD)) {
71                case AFMT_FULLDUPLEX:
72                        /*
73                         * this entry for cards with decent full duplex.
74                         */
75                        break;
76                case AFMT_FULLDUPLEX | AFMT_WEIRD:
77                        /* this is the sb16... */
78                        debug_msg("Weird Hardware\n");
79                        audio_format_change_encoding(ofmt, DEV_S8);
80                        break;
81                default:                /* no full duplex... */
82                        fprintf(stderr, "Sorry driver does support full duplex for this soundcard\n");
83                        luigi_audio_close(ad);
84                        return FALSE;
85                }
86               
87                assert(ofmt->channels == ifmt->channels);
88               
89                if (ifmt->channels == 2 && !(soundcaps.formats & AFMT_STEREO)) {
90                        fprintf(stderr,"Driver does not support stereo for this soundcard\n");
91                        luigi_audio_close(ad);
92                        return FALSE;
93                }
94
95                switch(ifmt->encoding) {
96                case DEV_PCMU: pa.rec_format = AFMT_MU_LAW; break;
97                case DEV_S8:   pa.rec_format = AFMT_S8;     break;
98                case DEV_S16:  pa.rec_format = AFMT_S16_LE; break;
99                }
100
101                switch(ofmt->encoding) {
102                case DEV_PCMU: pa.play_format = AFMT_MU_LAW; break;
103                case DEV_S8:   pa.play_format = AFMT_S8;     break;
104                case DEV_S16:  pa.play_format = AFMT_S16_LE; break;
105                }
106                pa.play_rate = ofmt->sample_rate;
107                pa.rec_rate = ifmt->sample_rate;
108                LUIGI_AUDIO_IOCTL(audio_fd, AIOSFMT, &pa);
109
110                sz.play_size = ofmt->bytes_per_block;
111                sz.rec_size  = ifmt->bytes_per_block;
112                LUIGI_AUDIO_IOCTL(audio_fd, AIOSSIZE, &sz);
113
114                LUIGI_AUDIO_IOCTL(audio_fd, AIOGSIZE, &sz);
115                debug_msg("rec size %d, play size %d bytes\n",
116                          sz.rec_size, sz.play_size);
117               
118                /* Set global gain/volume to maximum values. This may
119                 * fail on some cards, but shouldn't cause any harm
120                 * when it does..... */
121
122                LUIGI_AUDIO_IOCTL(audio_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume);
123                LUIGI_AUDIO_IOCTL(audio_fd, MIXER_WRITE(SOUND_MIXER_IGAIN), &volume);
124                /* Set the gain/volume properly. We use the controls for the  */
125                /* specific mixer channel to do this, relative to the global  */
126                /* maximum gain/volume we've just set...                      */
127                luigi_audio_set_igain(audio_fd, MAX_AMP / 2);
128                luigi_audio_set_ogain(audio_fd, MAX_AMP / 2);
129                /* Select microphone input. We can't select output source...  */
130                luigi_audio_iport_set(audio_fd, iport);
131                /* Turn off loopback from input to output... */
132                LUIGI_AUDIO_IOCTL(audio_fd, MIXER_WRITE(SOUND_MIXER_IMIX), &reclb);
133
134                if (luigi_error != 0) {
135                        /* Failed somewhere in initialization - reset error and exit*/
136                        luigi_audio_close(ad);
137                        luigi_error = 0;
138                        return FALSE;
139                }
140               
141                read(audio_fd, thedev, 64);
142                return TRUE;
143        } else {
144                perror("audio_open");
145                luigi_audio_close(ad);
146                return FALSE;
147        }
148}
149
150/* Close the audio device */
151void
152luigi_audio_close(audio_desc_t ad)
153{
154        UNUSED(ad);
155        if (audio_fd < 0) {
156                debug_msg("Device already closed!\n");
157                return;
158        }
159        luigi_audio_drain(audio_fd);
160        close(audio_fd);
161        audio_fd = -1;
162}
163
164/* Flush input buffer */
165void
166luigi_audio_drain(audio_desc_t ad)
167{
168        u_char buf[160];
169       
170        assert(audio_fd > 0);
171        UNUSED(ad);
172        while(luigi_audio_read(audio_fd, buf, 160) == 160);
173}
174
175int
176luigi_audio_duplex(audio_desc_t ad)
177{
178        /* We only ever open device full duplex! */
179        UNUSED(ad);
180        return TRUE;
181}
182
183int
184luigi_audio_read(audio_desc_t ad, u_char *buf, int read_bytes)
185{
186        int done, this_read;
187        int len;
188        /* Figure out how many bytes we can read before blocking... */
189
190        UNUSED(ad); assert(audio_fd > 0);
191
192        LUIGI_AUDIO_IOCTL(audio_fd, FIONREAD, &len);
193
194        len = min(len, read_bytes);
195
196        /* Read the data... */
197        done = 0;
198        while(done < len) {
199                this_read = read(audio_fd, (void*)buf, len - done);
200                done += this_read;
201                buf  += this_read;
202        }
203        return done;
204}
205
206int
207luigi_audio_write(audio_desc_t ad, u_char *buf, int write_bytes)
208{
209        int done;
210
211        UNUSED(ad); assert(audio_fd > 0);
212
213        done = write(audio_fd, (void*)buf, write_bytes);
214        if (done != write_bytes && errno != EINTR) {
215                perror("Error writing device");
216                return (write_bytes - done);
217        }
218
219        return write_bytes;
220}
221
222/* Set ops on audio device to be non-blocking */
223void
224luigi_audio_non_block(audio_desc_t ad)
225{
226        int             frag = 1;
227
228        UNUSED(ad); assert(audio_fd != -1);
229
230        LUIGI_AUDIO_IOCTL(audio_fd, SNDCTL_DSP_NONBLOCK, &frag);
231}
232
233/* Set ops on audio device to be blocking */
234void
235luigi_audio_block(audio_desc_t ad)
236{
237        int             frag = 0;
238       
239        UNUSED(ad); assert(audio_fd > 0);
240       
241        LUIGI_AUDIO_IOCTL(audio_fd, SNDCTL_DSP_NONBLOCK, &frag);
242}
243
244/* Gain and volume values are in the range 0 - MAX_AMP */
245void
246luigi_audio_set_ogain(audio_desc_t ad, int vol)
247{
248        int volume;
249
250        UNUSED(ad); assert(audio_fd > 0);
251
252        volume = vol << 8 | vol;
253        LUIGI_AUDIO_IOCTL(audio_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume);
254}
255
256int
257luigi_audio_get_ogain(audio_desc_t ad)
258{
259        int volume;
260
261        UNUSED(ad); assert(audio_fd > 0);
262
263        LUIGI_AUDIO_IOCTL(audio_fd, MIXER_READ(SOUND_MIXER_PCM), &volume);
264
265        return DEVICE_TO_RAT(volume & 0xff); /* Extract left channel volume */
266}
267
268void
269luigi_audio_loopback(audio_desc_t ad, int gain)
270{
271        UNUSED(ad); assert(audio_fd > 0);
272
273        gain = gain << 8 | gain;
274
275        LUIGI_AUDIO_IOCTL(audio_fd, MIXER_WRITE(SOUND_MIXER_IMIX), &gain);
276}
277
278void
279luigi_audio_oport_set(audio_desc_t ad, audio_port_t port)
280{
281        UNUSED(ad); assert(audio_fd > 0);
282        UNUSED(port);
283        return;
284}
285
286audio_port_t
287luigi_audio_oport_get(audio_desc_t ad)
288{
289        UNUSED(ad); assert(audio_fd > 0);
290        return LUIGI_SPEAKER;
291}
292
293int
294luigi_audio_oport_count(audio_desc_t ad)
295{
296        UNUSED(ad);
297        return 1;
298}
299
300static const audio_port_details_t out_ports[] = {{ LUIGI_SPEAKER, AUDIO_PORT_SPEAKER }};
301
302const audio_port_details_t*
303luigi_audio_oport_details(audio_desc_t ad, int idx)
304{
305        UNUSED(ad);
306        UNUSED(idx);
307        return out_ports;
308}
309
310void
311luigi_audio_set_igain(audio_desc_t ad, int gain)
312{
313        int volume = RAT_TO_DEVICE(gain) << 8 | RAT_TO_DEVICE(gain);
314
315        UNUSED(ad); assert(audio_fd > 0);
316
317        switch (iport) {
318        case LUIGI_MICROPHONE:
319                if (ioctl(audio_fd, MIXER_WRITE(SOUND_MIXER_MIC), &volume) < 0)
320                        perror("Setting gain");
321                break;
322        case LUIGI_LINE_IN:
323                if (ioctl(audio_fd, MIXER_WRITE(SOUND_MIXER_LINE), &volume) < 0)
324                        perror("Setting gain");
325                break;
326        case LUIGI_CD:
327                if (ioctl(audio_fd, MIXER_WRITE(SOUND_MIXER_CD), &volume) < 0) {
328                        perror("Setting gain");
329                }
330                break;
331        }
332        return;
333}
334
335int
336luigi_audio_get_igain(audio_desc_t ad)
337{
338        int volume;
339
340        UNUSED(ad); assert(audio_fd > 0);
341
342        switch (iport) {
343        case LUIGI_MICROPHONE:
344                LUIGI_AUDIO_IOCTL(audio_fd, MIXER_READ(SOUND_MIXER_MIC), &volume);
345                break;
346        case LUIGI_LINE_IN:
347                LUIGI_AUDIO_IOCTL(audio_fd, MIXER_READ(SOUND_MIXER_LINE), &volume);
348                break;
349        case LUIGI_CD:
350                LUIGI_AUDIO_IOCTL(audio_fd, MIXER_READ(SOUND_MIXER_CD), &volume);
351                break;
352        default:
353                debug_msg("ERROR: Unknown iport in audio_set_igain!\n");
354        }
355        return (DEVICE_TO_RAT(volume & 0xff));
356}
357
358static audio_port_details_t in_ports[] = {
359        { LUIGI_MICROPHONE, AUDIO_PORT_MICROPHONE},
360        { LUIGI_LINE_IN,    AUDIO_PORT_LINE_IN},
361        { LUIGI_CD,         AUDIO_PORT_CD}
362};
363
364#define NUM_IN_PORTS (sizeof(in_ports)/sizeof(in_ports[0]))
365
366void
367luigi_audio_iport_set(audio_desc_t ad, audio_port_t port)
368{
369        int recmask, gain, src;
370
371        UNUSED(ad); assert(audio_fd > 0);
372
373        if (ioctl(audio_fd, MIXER_READ(SOUND_MIXER_RECMASK), &recmask) == -1) {
374                perror("Unable to read recording mask");
375                return;
376        }
377
378        switch (port) {
379        case LUIGI_MICROPHONE:
380                src = SOUND_MASK_MIC;
381                break;
382        case LUIGI_LINE_IN:
383                src = SOUND_MASK_LINE;
384                break;
385        case LUIGI_CD:
386                src = SOUND_MASK_CD;
387                break;
388        }
389
390        gain = luigi_audio_get_igain(ad);
391        luigi_audio_set_igain(ad, 0);
392
393        if ((ioctl(audio_fd, MIXER_WRITE(SOUND_MIXER_RECSRC), &src) < 0)) {
394                return;
395        }
396
397        iport = port;
398        luigi_audio_set_igain(ad, gain);
399}
400
401audio_port_t
402luigi_audio_iport_get(audio_desc_t ad)
403{
404        UNUSED(ad); assert(audio_fd > 0);
405        return iport;
406}
407
408int
409luigi_audio_iport_count(audio_desc_t ad)
410{
411        UNUSED(ad);
412        return NUM_IN_PORTS;
413}
414
415const audio_port_details_t *
416luigi_audio_iport_details(audio_desc_t ad, int idx)
417{
418        UNUSED(ad);
419        assert(idx < (int)NUM_IN_PORTS && idx >= 0);
420        return in_ports + idx;
421}
422
423void
424luigi_audio_wait_for(audio_desc_t ad, int delay_ms)
425{
426        if (!luigi_audio_is_ready(ad)) {
427                usleep((unsigned int)delay_ms * 1000);
428        }
429}
430
431int 
432luigi_audio_is_ready(audio_desc_t ad)
433{
434        int avail;
435
436        UNUSED(ad);
437
438        LUIGI_AUDIO_IOCTL(audio_fd, FIONREAD, &avail);
439
440        return (avail >= sz.rec_size);
441}
442
443int 
444luigi_audio_supports(audio_desc_t ad, audio_format *fmt)
445{
446        snd_capabilities s;
447
448        UNUSED(ad);
449
450        if (luigi_error) debug_msg("Device error!");
451        luigi_error = 0;
452        LUIGI_AUDIO_IOCTL(audio_fd, AIOGCAP, &s);
453        if (!luigi_error) {
454                if ((unsigned)fmt->sample_rate < s.rate_min || (unsigned)fmt->sample_rate > s.rate_max) return FALSE;
455                if (fmt->channels == 1) return TRUE;                    /* Always supports mono */
456                assert(fmt->channels == 2);
457                if (s.formats & AFMT_STEREO) return TRUE;
458        }
459        return FALSE;
460}
461
462int
463luigi_audio_query_devices()
464{
465        FILE *f;
466        char buf[128], *p;
467        int n;
468
469        f = fopen("/dev/sndstat", "r");
470        if (f) {
471                while (!feof(f) && ndev < LUIGI_MAX_AUDIO_DEVICES) {
472                        p = fgets(buf, 128, f);
473                        n = sscanf(buf, "pcm%d: <%[A-z0-9 ]>", dev_ids + ndev, names[ndev]);
474                        if (p && n == 2) {
475                                debug_msg("dev (%d) name (%s)\n", dev_ids[ndev], names[ndev]);
476                                ndev++;
477                        }
478                }
479                fclose(f);
480        }
481        return (ndev);
482}
483
484int
485luigi_get_device_count()
486{
487        return ndev;
488}
489
490const char *
491luigi_get_device_name(audio_desc_t idx)
492{
493        if (idx >=0 && idx < ndev) {
494                return names[idx];
495        }
496        return NULL;
497}
498
499#endif /* FreeBSD */
Note: See TracBrowser for help on using the browser.