root/rat/trunk/auddev_atm.c @ 3083

Revision 3083, 13.7 KB (checked in by ucacoxh, 14 years ago)

- Typo corrections from Dimitris.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * FILE:     auddev_atm.c
3 * PROGRAM:  RAT
4 * AUTHORS:  Julian Cable, Dimitris Terzis
5 * MODS:     Orion Hodson
6 *
7 * auddev_atm acts like an audio device, only it reads and writes raw
8 * AAL1 ATM frames containing alaw coded samples.  It assumes that RAT
9 * is launched from a process that handles the atm set up and writes
10 * the atm file descriptor to a file called "atm_socket".  There are
11 * obviously other ways to communicate this info, but this suffices.
12 *
13 * The ATM stack in question is the Linux one, it may work with other
14 * stacks but we don't have access to any suitable ATM equipment at
15 * UCL to investigate (or even test this file).
16 *
17 * The real work here was done by Julian and Dimitris, who not only
18 * made initial version of this file, but also chased up ATM stack
19 * bugs.  OH fixed atm_audio_supports, simplified read/writes, and
20 * changed atm_audio_read to read as many frames as available.
21 *
22 * Copyright (c) 2000 Nortel Networks
23 *           (c) 1995-2000 University College London
24 * All rights reserved. 
25 */
26
27#ifndef HIDE_SOURCE_STRINGS
28static const char cvsid[] =
29        "$Id$";
30#endif /* HIDE_SOURCE_STRINGS */
31
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <fcntl.h>
35
36#include <atm.h>
37
38#include <string.h>
39#include "config_unix.h"
40#include "debug.h"
41#include "audio_types.h"
42#include "audio_fmt.h"
43#include "auddev_atm.h"
44#include "codec_g711.h"
45
46struct AUDIO
47{
48        int port;
49};
50
51static struct {
52        unsigned long atmhdr;
53        unsigned char rxresidue_buf[47];
54        unsigned char *rxresidue;
55        unsigned char txresidue[47];
56        int rxresidue_bytes;
57        int txresidue_bytes;
58        int seqno;
59        int monitor_gain;
60        int output_muted;
61        struct AUDIO play;
62        struct AUDIO record;
63}       dev_info;
64
65/* AAL1-specific ATM header bytes */
66static unsigned char aal1hdr[] = {0x00, 0x17, 0x2d, 0x3a, 0x4e, 0x59, 0x63, 0x74};
67
68static int audio_fd = -1;
69
70enum { AUDIO_LINE_OUT,  AUDIO_LINE_IN };
71
72#define bat_to_device(x)        ((x )
73#define device_to_bat(x)        ((x))
74
75static int atm_socket;
76
77int
78atm_audio_device_count()
79{
80        return 1;
81}
82
83const char*
84atm_audio_device_name(audio_desc_t ad)
85{
86        UNUSED(ad);
87        return "ATM Network Audio Device (PCM A-law)";
88}
89
90int
91atm_audio_supports(audio_desc_t ad, audio_format *fmt)
92{
93
94        UNUSED(ad);
95
96        /* Only check sample rate and channels */
97        if( fmt->sample_rate != 8000 ) return FALSE;
98        if( fmt->channels != 1 ) return FALSE;
99
100        return TRUE;
101}
102
103/* Try to open the audio device.                        */
104/* Essentially, we read an ATM socket file descriptor, */
105/* passed to RAT from the command line, from a file */
106/* Returns TRUE if ok, 0 otherwise. */
107int
108atm_audio_open(audio_desc_t ad, audio_format* ifmt, audio_format* ofmt)
109{
110
111        int len;
112        struct sockaddr_atmpvc vcc_address;
113        FILE *f = fopen("atm_socket", "r");
114
115        if (f == NULL) {
116                debug_msg("ATM socket file not found");
117                return FALSE;
118        }
119       
120        debug_msg("ATM audio device\n");
121       
122        fread(&atm_socket, sizeof(atm_socket), 1, f);
123        fclose(f);
124
125        len = sizeof(vcc_address);
126
127        if (audio_fd != -1) {
128                debug_msg("Device already open!");
129                atm_audio_close(ad);
130                return FALSE;
131        }
132
133        if (getsockopt(atm_socket, SOL_ATM, SO_ATMPVC, (char *)&vcc_address, &len) >= 0) {
134                unsigned gfc=0, vpi, vci, type=0, clp=0;
135                vpi = vcc_address.sap_addr.vpi;
136                vci = vcc_address.sap_addr.vci;
137                audio_fd = atm_socket;
138                dev_info.atmhdr = (gfc << ATM_HDR_GFC_SHIFT) | (vpi << ATM_HDR_VPI_SHIFT) |
139                        (vci << ATM_HDR_VCI_SHIFT) |       (type << ATM_HDR_PTI_SHIFT) | clp;
140               
141                dev_info.txresidue_bytes    = 0;
142                dev_info.rxresidue_bytes    = 0;
143                dev_info.rxresidue          = dev_info.rxresidue_buf;
144                dev_info.seqno              = 0;
145                memset(dev_info.txresidue, 0, sizeof(dev_info.txresidue));
146                memset(dev_info.rxresidue, 0, sizeof(dev_info.txresidue));
147               
148                dev_info.monitor_gain       = 0;
149                dev_info.output_muted       = 0; /* 0==not muted */
150                dev_info.play.port          = AUDIO_LINE_OUT;
151                dev_info.record.port        = AUDIO_LINE_IN;
152
153                audio_format_change_encoding(ifmt, DEV_PCMA);
154                audio_format_change_encoding(ofmt, DEV_PCMA);
155
156                debug_msg("ATM audio device open (fd=%d, vpi=%d, vci=%d)\n", audio_fd, vpi, vci);
157                atm_audio_drain(ad);
158
159                return audio_fd;
160        } else {
161                debug_msg("ATM socket descriptor is invalid");
162                return FALSE;
163        }
164}
165
166/* Close the audio device */
167void
168atm_audio_close(audio_desc_t ad)
169{
170        UNUSED(ad);
171        assert(audio_fd > 0);
172
173        if (audio_fd <= 0) {
174                debug_msg("Invalid desc");
175                return;
176        }
177
178        close(audio_fd);
179        audio_fd = -1;
180}
181
182/* Flush input buffer */
183void
184atm_audio_drain(audio_desc_t ad)
185{
186        UNUSED(ad); assert(audio_fd > 0);
187
188        ioctl(audio_fd, I_FLUSH, (caddr_t)FLUSHR);
189}
190
191/* Gain and volume values are in the range 0 - MAX_AMP */
192
193void
194atm_audio_set_igain(audio_desc_t ad, int gain)
195{
196        UNUSED(gain);
197        UNUSED(ad); assert(audio_fd > 0);
198}
199
200int
201atm_audio_get_igain(audio_desc_t ad)
202{
203        UNUSED(ad); assert(audio_fd > 0);
204
205        return 0;
206}
207
208void
209atm_audio_set_ogain(audio_desc_t ad, int vol)
210{
211        UNUSED(vol);
212        UNUSED(ad); assert(audio_fd > 0);
213}
214
215int
216atm_audio_get_ogain(audio_desc_t ad)
217{
218        UNUSED(ad); assert(audio_fd > 0);
219
220        return 0;
221}
222
223void
224atm_audio_loopback(audio_desc_t ad, int gain)
225{
226        UNUSED(gain);
227        UNUSED(ad); assert(audio_fd > 0);
228
229}
230
231#define ADA_CELL_SZ  52
232#define ADA_CELL_HEADER_SZ 5
233
234/* atm_audio_read: modified to read as many atm frames as are available (oh) */
235
236int
237atm_audio_read(audio_desc_t ad, u_char *buf, int buf_bytes)
238{
239        int len, avail, done = 0;
240        char cellbuf[ADA_CELL_SZ];
241
242        assert(dev_info.rxresidue_bytes >= 0);
243        assert(dev_info.rx_residue_bytes < sizeof(dev_info.rxresidue_buf));
244
245        if (dev_info.rxresidue_bytes > 0) {
246                if (buf_bytes >= dev_info.rxresidue_bytes) {
247                        /* big read that completely drains the residue */
248                        memcpy(buf, dev_info.rxresidue, dev_info.rxresidue_bytes);
249                        done                    += dev_info.rxresidue_bytes;
250                        dev_info.rxresidue       = dev_info.rxresidue_buf;
251                        dev_info.rxresidue_bytes = 0;
252                        debug_msg("read big\n");
253                } else {
254                        /* little read */
255                        memcpy(buf, dev_info.rxresidue, buf_bytes);
256                        dev_info.rxresidue_bytes -= buf_bytes;
257                        dev_info.rxresidue       += buf_bytes;
258                        done                     += buf_bytes;
259                        debug_msg("read small\n");
260                }
261        }
262
263        /* Read as much audio as is available */
264        len = 0;
265        while ((ioctl(audio_fd, FIONREAD, &avail) >= 0) &&
266               (buf_bytes - done) >= (ADA_CELL_SZ - ADA_CELL_HEADER_SZ)) {
267                len = read(audio_fd, cellbuf, sizeof(cellbuf));
268                if (len <= 0) {
269                        break;
270                }
271                assert(len == ADA_CELL_SZ);
272                memcpy(buf + done, cellbuf + ADA_CELL_HEADER_SZ, ADA_CELL_SZ - ADA_CELL_HEADER_SZ);
273                done += ADA_CELL_SZ - ADA_CELL_HEADER_SZ;
274                debug_msg("read frame %d\n", (int)cellbuf[4]);
275        }
276       
277        if (errno != 0) {
278                debug_msg("atm audio read error (%d): len %d avail %d done %d of %d bytes\n",
279                          errno, len, avail, done, buf_bytes);
280                /* avail =  0 ioctl failed          */
281                /* len   = -1 read failed           */
282                /* len   =  0 socket closed by peer */
283                errno = 0;
284                return done;
285        }
286
287        if (done < buf_bytes) {
288                /* Copy bytes left over into residue buffer */
289                int over;
290                assert(dev_info.rxresidue_bytes == 0);
291                assert(dev_info.rxresidue == dev_info.rxresidue_buf);
292
293                over = buf_bytes - done;
294                assert(over <= ADA_CELL_SZ - ADA_CELL_HEADER_SZ);
295
296                memcpy(dev_info.rxresidue,
297                       cellbuf + sizeof(cellbuf) - over,
298                       sizeof(cellbuf) - over);
299                dev_info.residue_bytes = over;
300                debug_msg("read residue %d\n", over);
301        }
302        return done;
303}
304
305
306int
307atm_audio_write(audio_desc_t ad, u_char *buf, int buf_bytes)
308{
309        int done;
310        unsigned char cellbuf[ADA_CELL_SZ];
311
312        UNUSED(ad); assert(audio_fd > 0);
313
314        done = 0;
315
316        /* if we have anything left from before put it in the output cell first
317         * and then fill the cell from the buffer, fixing pointers and counts
318         */
319        if (dev_info.txresidue_bytes > 0 &&
320            (buf_bytes + dev_info.txresidue_bytes) > (ADA_CELL_SZ - ADA_CELL_HEADER_SZ)) {
321                int rem = ADA_CELL_SZ - ADA_CELL_HEADER_SZ - dev_info.txresidue_bytes;
322                /* Fill in header */
323                memcpy(cellbuf, &dev_info.atmhdr, 4);
324                cellbuf[4] = aal1hdr[dev_info.seqno];
325                dev_info.seqno = (dev_info.seqno + 1) & 0x07; /* values 0-7 valid */
326                /* Fill in data   */
327                assert(dev_info.txresidue_bytes <= ADA_CELL_SZ - ADA_CELL_HEADER_SZ);
328                memcpy(cellbuf + ADA_CELL_HEADER_SZ, dev_info.txresidue, dev_info.txresidue_bytes);
329                if (rem > 0) {
330                        memcpy(cellbuf + ADA_CELL_HEADER_SZ + dev_info.txresidue_bytes, buf, rem);
331                }
332                write(audio_fd, (char *)cellbuf, ADA_CELL_SZ);
333                dev_info.txresidue_bytes = 0;
334                debug_msg("wrote frame %d using residue\n", dev_info.seqno);
335                done += rem;
336
337        }
338
339        while(done - buf_bytes >= ADA_CELL_SZ - ADA_CELL_HEADER_SZ) {
340                memcpy(cellbuf, &dev_info.atmhdr, 4);
341                cellbuf[4] = aal1hdr[dev_info.seqno];
342                memcpy(cellbuf + ADA_CELL_HEADER_SZ, buf + done, ADA_CELL_SZ - ADA_CELL_HEADER_SZ);
343                write(audio_fd, (char *)cellbuf, ADA_CELL_SZ);
344                done += ADA_CELL_SZ - ADA_CELL_HEADER_SZ;
345                debug_msg("Wrote frame %d %d %d\n", dev_info.seqno, done, buf_bytes);
346                dev_info.seqno = (dev_info.seqno + 1) & 0x07; /* values 0-7 valid */
347        }
348
349        if (buf_bytes - done > 0) {
350                dev_info.txresidue_bytes = done - buf_bytes;
351                assert(dev_info.txresidue_bytes <= ADA_CELL_SZ - ADA_CELL_HEADER_SZ);
352                memcpy(dev_info.txresidue, buf + done, dev_info.txresidue_bytes);
353        }
354
355        debug_msg("write residue left over %d\n", buf_bytes - done);
356
357        return buf_bytes;
358}
359
360/* Set ops on audio device to be non-blocking */
361void
362atm_audio_non_block(audio_desc_t ad)
363{
364        int     on = 1;
365
366        UNUSED(ad); assert(audio_fd > 0);
367
368        if (ioctl(audio_fd, FIONBIO, (char *)&on) < 0) {
369                debug_msg("Failed to set non blocking mode on audio device!\n");
370        } else {
371                debug_msg("Non-blocking mode set on ATM audio device (fd=%d)\n", audio_fd);
372        }
373}
374
375/* Set ops on audio device to block */
376void
377atm_audio_block(audio_desc_t ad)
378{
379        int     on = 0;
380
381        UNUSED(ad); assert(audio_fd > 0);
382
383        if (ioctl(audio_fd, FIONBIO, (char *)&on) < 0) {
384                debug_msg("Failed to set blocking mode on audio device!\n");
385        } else {
386                debug_msg("Blocking mode set on ATM audio device (fd=%d)\n", audio_fd);
387        }
388}
389
390
391static const audio_port_details_t out_ports[] = {
392        { AUDIO_LINE_OUT,  AUDIO_PORT_LINE_OUT }
393};
394
395#define NUM_OUT_PORTS (sizeof(out_ports)/sizeof(out_ports[0]))
396
397void
398atm_audio_oport_set(audio_desc_t ad, audio_port_t port)
399{
400        UNUSED(ad); assert(audio_fd > 0);
401
402        if (port != AUDIO_LINE_OUT) {
403                debug_msg("Port not recognized\n");
404                port = AUDIO_LINE_OUT;
405        }
406        dev_info.play.port = port;
407}
408
409audio_port_t
410atm_audio_oport_get(audio_desc_t ad)
411{
412        UNUSED(ad); assert(audio_fd > 0);
413        return (dev_info.play.port);
414}
415
416int
417atm_audio_oport_count(audio_desc_t ad)
418{
419        UNUSED(ad);
420        return (int)NUM_OUT_PORTS;
421}
422
423const audio_port_details_t*
424atm_audio_oport_details(audio_desc_t ad, int idx)
425{
426        UNUSED(ad);
427        if (idx >= 0 && idx < (int)NUM_OUT_PORTS) {
428                return &out_ports[idx];
429        }
430        return NULL;
431}
432
433static const audio_port_details_t in_ports[] = {
434        { AUDIO_LINE_IN,    AUDIO_PORT_LINE_IN}
435};
436
437#define NUM_IN_PORTS (sizeof(out_ports)/sizeof(out_ports[0]))
438
439void
440atm_audio_iport_set(audio_desc_t ad, audio_port_t port)
441{
442        UNUSED(ad); assert(audio_fd > 0);
443
444        if (port != AUDIO_LINE_IN ) {
445                port = AUDIO_LINE_IN;
446        }
447       
448        dev_info.record.port = port;
449}
450
451audio_port_t
452atm_audio_iport_get(audio_desc_t ad)
453{
454        UNUSED(ad); assert(audio_fd > 0);
455        return (dev_info.record.port);
456}
457
458int
459atm_audio_iport_count(audio_desc_t ad)
460{
461        UNUSED(ad);
462        return (int)NUM_IN_PORTS;
463}
464
465const audio_port_details_t*
466atm_audio_iport_details(audio_desc_t ad, int idx)
467{
468        UNUSED(ad);
469        if (idx >= 0 && idx < (int)NUM_IN_PORTS) {
470                return &in_ports[idx];
471        }
472        return NULL;
473}
474
475int
476atm_audio_duplex(audio_desc_t ad)
477{
478        UNUSED(ad); assert(audio_fd > 0);
479
480        return 1;
481}
482
483static int
484atm_audio_select(audio_desc_t ad, int delay_us)
485{
486        fd_set rfds;
487        struct timeval tv, s1, s2;
488
489        UNUSED(ad); assert(audio_fd > 0);
490
491        tv.tv_sec = 0;
492        tv.tv_usec = delay_us;
493
494        FD_ZERO(&rfds);
495        FD_SET(audio_fd, &rfds);
496
497        gettimeofday (&s1, 0);
498        select(audio_fd+1, &rfds, NULL, NULL, &tv);
499        gettimeofday (&s2, 0);
500
501        s2.tv_usec -= s1.tv_usec;
502        s2.tv_sec  -= s1.tv_sec;
503
504        if (s2.tv_usec < 0) {
505                s2.tv_usec += 1000000;
506                s2.tv_sec  -= 1;
507        }
508
509        return FD_ISSET(audio_fd, &rfds);
510}
511
512void
513atm_audio_wait_for(audio_desc_t ad, int delay_ms)
514{
515        UNUSED(ad); assert(audio_fd > 0);
516        atm_audio_select(ad, delay_ms * 1000);
517}
518
519int
520atm_audio_is_ready(audio_desc_t ad)
521{
522        UNUSED(ad); assert(audio_fd > 0);
523        return atm_audio_select(ad, 0);
524}
Note: See TracBrowser for help on using the browser.