Version 0.1.8 from FTP
[asterisk/asterisk.git] / frame.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Frame manipulation routines
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <asterisk/frame.h>
15 #include <asterisk/logger.h>
16 #include <asterisk/options.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <errno.h>
21
22 /*
23  * Important: I should be made more efficient.  Frame headers should
24  * most definitely be cached
25  */
26
27 void ast_frfree(struct ast_frame *fr)
28 {
29         if (fr->mallocd & AST_MALLOCD_DATA) {
30                 if (fr->data) 
31                         free(fr->data - fr->offset);
32         }
33         if (fr->mallocd & AST_MALLOCD_SRC) {
34                 if (fr->src)
35                         free(fr->src);
36         }
37         if (fr->mallocd & AST_MALLOCD_HDR) {
38                 free(fr);
39         }
40 }
41
42 void ast_frchain(struct ast_frame_chain *fc)
43 {
44         struct ast_frame_chain *last;
45         while(fc) {
46                 last = fc;
47                 fc = fc->next;
48                 if (last->fr)
49                         ast_frfree(last->fr);
50                 free(last);
51         }
52 }
53
54 struct ast_frame *ast_frisolate(struct ast_frame *fr)
55 {
56         struct ast_frame *out;
57         if (!(fr->mallocd & AST_MALLOCD_HDR)) {
58                 /* Allocate a new header if needed */
59                 out = malloc(sizeof(struct ast_frame));
60                 if (!out) {
61                         ast_log(LOG_WARNING, "Out of memory\n");
62                         return NULL;
63                 }
64                 out->frametype = fr->frametype;
65                 out->subclass = fr->subclass;
66                 out->datalen = 0;
67                 out->timelen = fr->timelen;
68                 out->offset = 0;
69                 out->src = NULL;
70                 out->data = NULL;
71         } else {
72                 out = fr;
73         }
74         if (!(fr->mallocd & AST_MALLOCD_SRC)) {
75                 if (fr->src)
76                         out->src = strdup(fr->src);
77         } else
78                 out->src = fr->src;
79         if (!(fr->mallocd & AST_MALLOCD_DATA))  {
80                 out->data = malloc(fr->datalen + AST_FRIENDLY_OFFSET);
81                 if (!out->data) {
82                         free(out);
83                         ast_log(LOG_WARNING, "Out of memory\n");
84                         return NULL;
85                 }
86                 out->data += AST_FRIENDLY_OFFSET;
87                 out->offset = AST_FRIENDLY_OFFSET;
88                 out->datalen = fr->datalen;
89                 memcpy(out->data, fr->data, fr->datalen);
90         }
91         out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
92         return out;
93 }
94
95 struct ast_frame *ast_frdup(struct ast_frame *f)
96 {
97         struct ast_frame *ret;
98         int p;
99         p = f->mallocd;
100         f->mallocd = 0;
101         /* Make frisolate think this is a 100% static frame, and make a duplicate */
102         ret = ast_frisolate(f);
103         /* Restore its true malloc status */
104         f->mallocd = p;
105         return ret;
106 }
107
108 struct ast_frame *ast_fr_fdread(int fd)
109 {
110         char buf[4096];
111         int res;
112         int ttl = sizeof(struct ast_frame);
113         struct ast_frame *f = (struct ast_frame *)buf;
114         /* Read a frame directly from there.  They're always in the
115            right format. */
116         
117         while(ttl) {
118                 res = read(fd, buf, ttl);
119                 if (res < 0) {
120                         ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
121                         return NULL;
122                 }
123                 ttl -= res;
124         }
125         
126         /* read the frame header */
127         f->mallocd = 0;
128         /* Re-write data position */
129         f->data = buf + sizeof(struct ast_frame);
130         f->offset = 0;
131         /* Forget about being mallocd */
132         f->mallocd = 0;
133         /* Re-write the source */
134         f->src = __FUNCTION__;
135         if (f->datalen > sizeof(buf) - sizeof(struct ast_frame)) {
136                 /* Really bad read */
137                 ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
138                 return NULL;
139         }
140         if (f->datalen) {
141                 if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
142                         /* Bad read */
143                         ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
144                         return NULL;
145                 }
146         }
147         if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
148                 return NULL;
149         }
150         return ast_frisolate(f);
151 }
152
153 /* Some convenient routines for sending frames to/from stream or datagram
154    sockets, pipes, etc (maybe even files) */
155
156 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
157 {
158         /* Write the frame exactly */
159         if (write(fd, frame, sizeof(struct ast_frame)) != sizeof(struct ast_frame)) {
160                 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
161                 return -1;
162         }
163         if (write(fd, frame->data, frame->datalen) != frame->datalen) {
164                 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
165                 return -1;
166         }
167         return 0;
168 }
169
170 int ast_fr_fdhangup(int fd)
171 {
172         struct ast_frame hangup = {
173                 AST_FRAME_CONTROL,
174                 AST_CONTROL_HANGUP
175         };
176         return ast_fr_fdwrite(fd, &hangup);
177 }
178
179 int ast_getformatbyname(char *name)
180 {
181         if (!strcasecmp(name, "g723.1")) 
182                 return AST_FORMAT_G723_1;
183         else if (!strcasecmp(name, "gsm"))
184                 return AST_FORMAT_GSM;
185         else if (!strcasecmp(name, "ulaw"))
186                 return AST_FORMAT_ULAW;
187         else if (!strcasecmp(name, "alaw"))
188                 return AST_FORMAT_ALAW;
189         else if (!strcasecmp(name, "mp3"))
190                 return AST_FORMAT_MP3;
191         else if (!strcasecmp(name, "slinear"))
192                 return AST_FORMAT_SLINEAR;
193         else if (!strcasecmp(name, "lpc10"))
194                 return AST_FORMAT_LPC10;
195         else if (!strcasecmp(name, "adpcm"))
196                 return AST_FORMAT_ADPCM;
197         else if (!strcasecmp(name, "all"))
198                 return 0x7FFFFFFF;
199         return 0;
200 }