root/rat/trunk/auddev_luigi.c @ 2401

Revision 2401, 12.9 KB (checked in by ucacoxh, 15 years ago)

- moved the loopback setting during the init to past the bail check
since sb would fail to set loopback and this was causing device
opening to misreport as failing.

  • 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
132                if (luigi_error != 0) {
133                        /* Failed somewhere in initialization - reset error and exit*/
134                        luigi_audio_close(ad);
135                        luigi_error = 0;
136                        return FALSE;
137                }
138
139                /* Turn off loopback from input to output... not fatal so
140                 * after error check.
141                 */
142                LUIGI_AUDIO_IOCTL(audio_fd, MIXER_WRITE(SOUND_MIXER_IMIX), &reclb);
143
144                read(audio_fd, thedev, 64);
145                return TRUE;
146        } else {
147                perror("audio_open");
148                luigi_audio_close(ad);
149                return FALSE;
150        }
151}
152
153/* Close the audio device */
154void
155luigi_audio_close(audio_desc_t ad)
156{
157        UNUSED(ad);
158        if (audio_fd < 0) {
159                debug_msg("Device already closed!\n");
160                return;
161        }
162        luigi_audio_drain(audio_fd);
163        close(audio_fd);
164        audio_fd = -1;
165}
166
167/* Flush input buffer */
168void
169luigi_audio_drain(audio_desc_t ad)
170{
171        u_char buf[160];
172       
173        assert(audio_fd > 0);
174        UNUSED(ad);
175        while(luigi_audio_read(audio_fd, buf, 160) == 160);
176}
177
178int
179luigi_audio_duplex(audio_desc_t ad)
180{
181        /* We only ever open device full duplex! */
182        UNUSED(ad);
183        return TRUE;
184}
185
186int
187luigi_audio_read(audio_desc_t ad, u_char *buf, int read_bytes)
188{
189        int done, this_read;
190        int len;
191        /* Figure out how many bytes we can read before blocking... */
192
193        UNUSED(ad); assert(audio_fd > 0);
194
195        LUIGI_AUDIO_IOCTL(audio_fd, FIONREAD, &len);
196
197        len = min(len, read_bytes);
198
199        /* Read the data... */
200        done = 0;
201        while(done < len) {
202                this_read = read(audio_fd, (void*)buf, len - done);
203                done += this_read;
204                buf  += this_read;
205        }
206        return done;
207}
208
209int
210luigi_audio_write(audio_desc_t ad, u_char *buf, int write_bytes)
211{
212        int done;
213
214        UNUSED(ad); assert(audio_fd > 0);
215
216        done = write(audio_fd, (void*)buf, write_bytes);
217        if (done != write_bytes && errno != EINTR) {
218                perror("Error writing device");
219                return (write_bytes - done);
220        }
221
222        return write_bytes;
223}
224
225/* Set ops on audio device to be non-blocking */
226void
227luigi_audio_non_block(audio_desc_t ad)
228{
229        int             frag = 1;
230
231        UNUSED(ad); assert(audio_fd != -1);
232
233        LUIGI_AUDIO_IOCTL(audio_fd, SNDCTL_DSP_NONBLOCK, &frag);
234}
235
236/* Set ops on audio device to be blocking */
237void
238luigi_audio_block(audio_desc_t ad)
239{
240        int             frag = 0;
241       
242        UNUSED(ad); assert(audio_fd > 0);
243       
244        LUIGI_AUDIO_IOCTL(audio_fd, SNDCTL_DSP_NONBLOCK, &frag);
245}
246
247/* Gain and volume values are in the range 0 - MAX_AMP */
248void
249luigi_audio_set_ogain(audio_desc_t ad, int vol)
250{
251        int volume;
252
253        UNUSED(ad); assert(audio_fd > 0);
254
255        volume = vol << 8 | vol;
256        LUIGI_AUDIO_IOCTL(audio_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume);
257}
258
259int
260luigi_audio_get_ogain(audio_desc_t ad)
261{
262        int volume;
263
264        UNUSED(ad); assert(audio_fd > 0);
265
266        LUIGI_AUDIO_IOCTL(audio_fd, MIXER_READ(SOUND_MIXER_PCM), &volume);
267
268        return DEVICE_TO_RAT(volume & 0xff); /* Extract left channel volume */
269}
270
271void
272luigi_audio_loopback(audio_desc_t ad, int gain)
273{
274        UNUSED(ad); assert(audio_fd > 0);
275
276        gain = gain << 8 | gain;
277
278        LUIGI_AUDIO_IOCTL(audio_fd, MIXER_WRITE(SOUND_MIXER_IMIX), &gain);
279}
280
281void
282luigi_audio_oport_set(audio_desc_t ad, audio_port_t port)
283{
284        UNUSED(ad); assert(audio_fd > 0);
285        UNUSED(port);
286        return;
287}
288
289audio_port_t
290luigi_audio_oport_get(audio_desc_t ad)
291{
292        UNUSED(ad); assert(audio_fd > 0);
293        return LUIGI_SPEAKER;
294}
295
296int
297luigi_audio_oport_count(audio_desc_t ad)
298{
299        UNUSED(ad);
300        return 1;
301}
302
303static const audio_port_details_t out_ports[] = {{ LUIGI_SPEAKER, AUDIO_PORT_SPEAKER }};
304
305const audio_port_details_t*
306luigi_audio_oport_details(audio_desc_t ad, int idx)
307{
308        UNUSED(ad);
309        UNUSED(idx);
310        return out_ports;
311}
312
313void
314luigi_audio_set_igain(audio_desc_t ad, int gain)
315{
316        int volume = RAT_TO_DEVICE(gain) << 8 | RAT_TO_DEVICE(gain);
317
318        UNUSED(ad); assert(audio_fd > 0);
319
320        switch (iport) {
321        case LUIGI_MICROPHONE:
322                if (ioctl(audio_fd, MIXER_WRITE(SOUND_MIXER_MIC), &volume) < 0)
323                        perror("Setting gain");
324                break;
325        case LUIGI_LINE_IN:
326                if (ioctl(audio_fd, MIXER_WRITE(SOUND_MIXER_LINE), &volume) < 0)
327                        perror("Setting gain");
328                break;
329        case LUIGI_CD:
330                if (ioctl(audio_fd, MIXER_WRITE(SOUND_MIXER_CD), &volume) < 0) {
331                        perror("Setting gain");
332                }
333                break;
334        }
335        return;
336}
337
338int
339luigi_audio_get_igain(audio_desc_t ad)
340{
341        int volume;
342
343        UNUSED(ad); assert(audio_fd > 0);
344
345        switch (iport) {
346        case LUIGI_MICROPHONE:
347                LUIGI_AUDIO_IOCTL(audio_fd, MIXER_READ(SOUND_MIXER_MIC), &volume);
348                break;
349        case LUIGI_LINE_IN:
350                LUIGI_AUDIO_IOCTL(audio_fd, MIXER_READ(SOUND_MIXER_LINE), &volume);
351                break;
352        case LUIGI_CD:
353                LUIGI_AUDIO_IOCTL(audio_fd, MIXER_READ(SOUND_MIXER_CD), &volume);
354                break;
355        default:
356                debug_msg("ERROR: Unknown iport in audio_set_igain!\n");
357        }
358        return (DEVICE_TO_RAT(volume & 0xff));
359}
360
361static audio_port_details_t in_ports[] = {
362        { LUIGI_MICROPHONE, AUDIO_PORT_MICROPHONE},
363        { LUIGI_LINE_IN,    AUDIO_PORT_LINE_IN},
364        { LUIGI_CD,         AUDIO_PORT_CD}
365};
366
367#define NUM_IN_PORTS (sizeof(in_ports)/sizeof(in_ports[0]))
368
369void
370luigi_audio_iport_set(audio_desc_t ad, audio_port_t port)
371{
372        int recmask, gain, src;
373
374        UNUSED(ad); assert(audio_fd > 0);
375
376        if (ioctl(audio_fd, MIXER_READ(SOUND_MIXER_RECMASK), &recmask) == -1) {
377                perror("Unable to read recording mask");
378                return;
379        }
380
381        switch (port) {
382        case LUIGI_MICROPHONE:
383                src = SOUND_MASK_MIC;
384                break;
385        case LUIGI_LINE_IN:
386                src = SOUND_MASK_LINE;
387                break;
388        case LUIGI_CD:
389                src = SOUND_MASK_CD;
390                break;
391        }
392
393        gain = luigi_audio_get_igain(ad);
394        luigi_audio_set_igain(ad, 0);
395
396        if ((ioctl(audio_fd, MIXER_WRITE(SOUND_MIXER_RECSRC), &src) < 0)) {
397                return;
398        }
399
400        iport = port;
401        luigi_audio_set_igain(ad, gain);
402}
403
404audio_port_t
405luigi_audio_iport_get(audio_desc_t ad)
406{
407        UNUSED(ad); assert(audio_fd > 0);
408        return iport;
409}
410
411int
412luigi_audio_iport_count(audio_desc_t ad)
413{
414        UNUSED(ad);
415        return NUM_IN_PORTS;
416}
417
418const audio_port_details_t *
419luigi_audio_iport_details(audio_desc_t ad, int idx)
420{
421        UNUSED(ad);
422        assert(idx < (int)NUM_IN_PORTS && idx >= 0);
423        return in_ports + idx;
424}
425
426void
427luigi_audio_wait_for(audio_desc_t ad, int delay_ms)
428{
429        if (!luigi_audio_is_ready(ad)) {
430                usleep((unsigned int)delay_ms * 1000);
431        }
432}
433
434int 
435luigi_audio_is_ready(audio_desc_t ad)
436{
437        int avail;
438
439        UNUSED(ad);
440
441        LUIGI_AUDIO_IOCTL(audio_fd, FIONREAD, &avail);
442
443        return (avail >= sz.rec_size);
444}
445
446int 
447luigi_audio_supports(audio_desc_t ad, audio_format *fmt)
448{
449        snd_capabilities s;
450
451        UNUSED(ad);
452
453        if (luigi_error) debug_msg("Device error!");
454        luigi_error = 0;
455        LUIGI_AUDIO_IOCTL(audio_fd, AIOGCAP, &s);
456        if (!luigi_error) {
457                if ((unsigned)fmt->sample_rate < s.rate_min || (unsigned)fmt->sample_rate > s.rate_max) return FALSE;
458                if (fmt->channels == 1) return TRUE;                    /* Always supports mono */
459                assert(fmt->channels == 2);
460                if (s.formats & AFMT_STEREO) return TRUE;
461        }
462        return FALSE;
463}
464
465int
466luigi_audio_query_devices()
467{
468        FILE *f;
469        char buf[128], *p;
470        int n;
471
472        f = fopen("/dev/sndstat", "r");
473        if (f) {
474                while (!feof(f) && ndev < LUIGI_MAX_AUDIO_DEVICES) {
475                        p = fgets(buf, 128, f);
476                        n = sscanf(buf, "pcm%d: <%[A-z0-9 ]>", dev_ids + ndev, names[ndev]);
477                        if (p && n == 2) {
478                                debug_msg("dev (%d) name (%s)\n", dev_ids[ndev], names[ndev]);
479                                ndev++;
480                        }
481                }
482                fclose(f);
483        }
484        return (ndev);
485}
486
487int
488luigi_get_device_count()
489{
490        return ndev;
491}
492
493const char *
494luigi_get_device_name(audio_desc_t idx)
495{
496        if (idx >=0 && idx < ndev) {
497                return names[idx];
498        }
499        return NULL;
500}
501
502#endif /* FreeBSD */
Note: See TracBrowser for help on using the browser.