root/rat/trunk/auddev_atm.c @ 3082

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

- Added auddev_atm.[ch]. Not sure whether it works since we don't have a

suitable atm setup. I've debugged and cleaned up code that Dimitris
Terzis sent for inspection and see no reason why this shouldn't work now.

  • 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        UNUSED(ad); assert(audio_fd > 0);
243
244        assert(dev_info.rxresidue_bytes >= 0);
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                } else {
253                        /* little read */
254                        memcpy(buf, dev_info.rxresidue, buf_bytes);
255                        dev_info.rxresidue_bytes -= buf_bytes;
256                        dev_info.rxresidue       += buf_bytes;
257                        done                     += buf_bytes;
258                }
259        }
260
261        /* Read as much audio as is available */
262        len = 0;
263        while ((ioctl(audio_fd, FIONREAD, &avail) >= 0) &&
264               (buf_bytes - done) >= (ADA_CELL_SZ - ADA_CELL_HEADER_SZ)) {
265                len = read(audio_fd, cellbuf, sizeof(cellbuf));
266                if (len <= 0) {
267                        break;
268                }
269                assert(len == CELL_SZ);
270                memcpy(buf + done, cellbuf + ADA_CELL_HEADER_SZ, ADA_CELL_SZ - ADA_CELL_HEADER_SZ);
271                done += ADA_CELL_SZ - ADA_CELL_HEADER_SZ;
272        }
273       
274        if (errno != 0) {
275                debug_msg("atm audio read error (%d): len %d avail %d done %d of %d bytes\n",
276                          errno, len, avail, done, buf_bytes);
277                /* avail =  0 ioctl failed          */
278                /* len   = -1 read failed           */
279                /* len   =  0 socket closed by peer */
280                errno = 0;
281                return done;
282        }
283
284        if (done < buf_bytes) {
285                /* Copy bytes left over into residue buffer */
286                int over;
287                assert(dev_info.rxresidue_bytes == 0);
288                assert(dev_info.rxresidue == dev_info.rxresidue_buf);
289
290                over = buf_bytes - done;
291                assert(over < ADA_CELL_SZ);
292
293                memcpy(dev_info.rxresidue,
294                       cellbuf + sizeof(cellbuf) - over,
295                       sizeof(cellbuf) - over);
296                dev_info.residue_bytes = over;
297        }
298        return done;
299}
300
301
302int
303atm_audio_write(audio_desc_t ad, u_char *buf, int buf_bytes)
304{
305        int done;
306        unsigned char cellbuf[52];
307
308        UNUSED(ad); assert(audio_fd > 0);
309
310        done = 0;
311
312        /* if we have anything left from before put it in the output cell first
313         * and then fill the cell from the buffer, fixing pointers and counts
314         */
315        if (dev_info.txresidue_bytes > 0 && buf_bytes + dev_info.txresidue_bytes > ADA_CELL_SZ - ADA_CELL_HEADER_SZ) {
316                int rem = ADA_CELL_SZ - ADA_CELL_HEADER_SZ - dev_info.txresidue_bytes;
317                memcpy(cellbuf, &dev_info.atmhdr, 4);
318                cellbuf[4] = aal1hdr[dev_info.seqno];
319                dev_info.seq_no = (dev_info.seqno + 1) & 0x07; /* values 0-7 valid */
320                memcpy(cellbuf + ATM_CELL_HEADER_SZ, dev_info.txresidue, dev_info.txresidue_bytes);
321                memcpy(cellbuf + ATM_CELL_HEADER_SZ + dev_info.txresidue_bytes, buf, rem);
322                write(audio_fd, (char *)cellbuf, ATM_CELL_SZ);
323                dev_info.txresidue_bytes = 0;
324                done += rem;
325        }
326
327        while(done - buf_bytes >= ADA_CELL_SZ - ADA_CELL_HEADER_SZ) {
328                memcpy(cellbuf, &dev_info.atmhdr, 4);
329                cellbuf[4] = aal1hdr[dev_info.seqno];
330                memcpy(cellbuf + ADA_CELL_HEADER_SZ, buf + done, ADA_CELL_SZ - ADA_CELL_HEADER_SZ);
331                write(audio_fd, (char *)cellbuf, ADA_CELL_SZ);
332                done += ADA_CELL_SZ - ADA_CELL_HEADER_SZ;
333                dev_info.seq_no = (dev_info.seqno + 1) & 0x07; /* values 0-7 valid */
334        }
335
336        if (buf_bytes - done > 0) {
337                dev_info.txresidue_bytes = done - buf_bytes;
338                memcpy(dev_info.txresidue, buf + done, dev_info.txresidue_bytes);
339        }
340
341        return buf_bytes;
342}
343
344/* Set ops on audio device to be non-blocking */
345void
346atm_audio_non_block(audio_desc_t ad)
347{
348        int     on = 1;
349
350        UNUSED(ad); assert(audio_fd > 0);
351
352        if (ioctl(audio_fd, FIONBIO, (char *)&on) < 0) {
353                debug_msg("Failed to set non blocking mode on audio device!\n");
354        } else {
355                debug_msg("Non-blocking mode set on ATM audio device (fd=%d)\n", audio_fd);
356        }
357}
358
359/* Set ops on audio device to block */
360void
361atm_audio_block(audio_desc_t ad)
362{
363        int     on = 0;
364
365        UNUSED(ad); assert(audio_fd > 0);
366
367        if (ioctl(audio_fd, FIONBIO, (char *)&on) < 0) {
368                debug_msg("Failed to set blocking mode on audio device!\n");
369        } else {
370                debug_msg("Blocking mode set on ATM audio device (fd=%d)\n", audio_fd);
371        }
372}
373
374
375static const audio_port_details_t out_ports[] = {
376        { AUDIO_LINE_OUT,  AUDIO_PORT_LINE_OUT }
377};
378
379#define NUM_OUT_PORTS (sizeof(out_ports)/sizeof(out_ports[0]))
380
381void
382atm_audio_oport_set(audio_desc_t ad, audio_port_t port)
383{
384        UNUSED(ad); assert(audio_fd > 0);
385
386        if (port != AUDIO_LINE_OUT) {
387                debug_msg("Port not recognized\n");
388                port = AUDIO_LINE_OUT;
389        }
390        dev_info.play.port = port;
391}
392
393audio_port_t
394atm_audio_oport_get(audio_desc_t ad)
395{
396        UNUSED(ad); assert(audio_fd > 0);
397        return (dev_info.play.port);
398}
399
400int
401atm_audio_oport_count(audio_desc_t ad)
402{
403        UNUSED(ad);
404        return (int)NUM_OUT_PORTS;
405}
406
407const audio_port_details_t*
408atm_audio_oport_details(audio_desc_t ad, int idx)
409{
410        UNUSED(ad);
411        if (idx >= 0 && idx < (int)NUM_OUT_PORTS) {
412                return &out_ports[idx];
413        }
414        return NULL;
415}
416
417static const audio_port_details_t in_ports[] = {
418        { AUDIO_LINE_IN,    AUDIO_PORT_LINE_IN}
419};
420
421#define NUM_IN_PORTS (sizeof(out_ports)/sizeof(out_ports[0]))
422
423void
424atm_audio_iport_set(audio_desc_t ad, audio_port_t port)
425{
426        UNUSED(ad); assert(audio_fd > 0);
427
428        if (port != AUDIO_LINE_IN ) {
429                port = AUDIO_LINE_IN;
430        }
431       
432        dev_info.record.port = port;
433}
434
435audio_port_t
436atm_audio_iport_get(audio_desc_t ad)
437{
438        UNUSED(ad); assert(audio_fd > 0);
439        return (dev_info.record.port);
440}
441
442int
443atm_audio_iport_count(audio_desc_t ad)
444{
445        UNUSED(ad);
446        return (int)NUM_IN_PORTS;
447}
448
449const audio_port_details_t*
450atm_audio_iport_details(audio_desc_t ad, int idx)
451{
452        UNUSED(ad);
453        if (idx >= 0 && idx < (int)NUM_IN_PORTS) {
454                return &in_ports[idx];
455        }
456        return NULL;
457}
458
459int
460atm_audio_duplex(audio_desc_t ad)
461{
462        UNUSED(ad); assert(audio_fd > 0);
463
464        return 1;
465}
466
467static int
468atm_audio_select(audio_desc_t ad, int delay_us)
469{
470        fd_set rfds;
471        struct timeval tv, s1, s2;
472
473        UNUSED(ad); assert(audio_fd > 0);
474
475        tv.tv_sec = 0;
476        tv.tv_usec = delay_us;
477
478        FD_ZERO(&rfds);
479        FD_SET(audio_fd, &rfds);
480
481        gettimeofday (&s1, 0);
482        select(audio_fd+1, &rfds, NULL, NULL, &tv);
483        gettimeofday (&s2, 0);
484
485        s2.tv_usec -= s1.tv_usec;
486        s2.tv_sec  -= s1.tv_sec;
487
488        if (s2.tv_usec < 0) {
489                s2.tv_usec += 1000000;
490                s2.tv_sec  -= 1;
491        }
492
493        return FD_ISSET(audio_fd, &rfds);
494}
495
496void
497atm_audio_wait_for(audio_desc_t ad, int delay_ms)
498{
499        UNUSED(ad); assert(audio_fd > 0);
500        atm_audio_select(ad, delay_ms * 1000);
501}
502
503int
504atm_audio_is_ready(audio_desc_t ad)
505{
506        UNUSED(ad); assert(audio_fd > 0);
507        return atm_audio_select(ad, 0);
508}
Note: See TracBrowser for help on using the browser.