Version 0.1.9 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 <asterisk/cli.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <pthread.h>
23 #include "asterisk.h"
24
25 #ifdef TRACE_FRAMES
26 static int headers = 0;
27 static struct ast_frame *headerlist = NULL;
28 static pthread_mutex_t framelock = PTHREAD_MUTEX_INITIALIZER;
29 #endif
30
31 static struct ast_frame *ast_frame_header_new(void)
32 {
33         struct ast_frame *f;
34         f = malloc(sizeof(struct ast_frame));
35 #ifdef TRACE_FRAMES
36         if (f) {
37                 headers++;
38                 f->prev = NULL;
39                 pthread_mutex_lock(&framelock);
40                 f->next = headerlist;
41                 if (headerlist)
42                         headerlist->prev = f;
43                 headerlist = f;
44                 pthread_mutex_unlock(&framelock);
45         }
46 #endif  
47         return f;
48 }
49
50 /*
51  * Important: I should be made more efficient.  Frame headers should
52  * most definitely be cached
53  */
54
55 void ast_frfree(struct ast_frame *fr)
56 {
57         if (fr->mallocd & AST_MALLOCD_DATA) {
58                 if (fr->data) 
59                         free(fr->data - fr->offset);
60         }
61         if (fr->mallocd & AST_MALLOCD_SRC) {
62                 if (fr->src)
63                         free(fr->src);
64         }
65         if (fr->mallocd & AST_MALLOCD_HDR) {
66 #ifdef TRACE_FRAMES
67                 headers--;
68                 pthread_mutex_lock(&framelock);
69                 if (fr->next)
70                         fr->next->prev = fr->prev;
71                 if (fr->prev)
72                         fr->prev->next = fr->next;
73                 else
74                         headerlist = fr->next;
75                 pthread_mutex_unlock(&framelock);
76 #endif                  
77                 free(fr);
78         }
79 }
80
81 struct ast_frame *ast_frisolate(struct ast_frame *fr)
82 {
83         struct ast_frame *out;
84         if (!(fr->mallocd & AST_MALLOCD_HDR)) {
85                 /* Allocate a new header if needed */
86                 out = ast_frame_header_new();
87                 if (!out) {
88                         ast_log(LOG_WARNING, "Out of memory\n");
89                         return NULL;
90                 }
91                 out->frametype = fr->frametype;
92                 out->subclass = fr->subclass;
93                 out->datalen = 0;
94                 out->timelen = fr->timelen;
95                 out->offset = 0;
96                 out->src = NULL;
97                 out->data = NULL;
98         } else {
99                 out = fr;
100         }
101         if (!(fr->mallocd & AST_MALLOCD_SRC)) {
102                 if (fr->src)
103                         out->src = strdup(fr->src);
104         } else
105                 out->src = fr->src;
106         if (!(fr->mallocd & AST_MALLOCD_DATA))  {
107                 out->data = malloc(fr->datalen + AST_FRIENDLY_OFFSET);
108                 if (!out->data) {
109                         free(out);
110                         ast_log(LOG_WARNING, "Out of memory\n");
111                         return NULL;
112                 }
113                 out->data += AST_FRIENDLY_OFFSET;
114                 out->offset = AST_FRIENDLY_OFFSET;
115                 out->datalen = fr->datalen;
116                 memcpy(out->data, fr->data, fr->datalen);
117         }
118         out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
119         return out;
120 }
121
122 struct ast_frame *ast_frdup(struct ast_frame *f)
123 {
124         struct ast_frame *ret;
125         int p;
126         p = f->mallocd;
127         f->mallocd = 0;
128         /* Make frisolate think this is a 100% static frame, and make a duplicate */
129         ret = ast_frisolate(f);
130         /* Restore its true malloc status */
131         f->mallocd = p;
132         return ret;
133 }
134
135 struct ast_frame *ast_fr_fdread(int fd)
136 {
137         char buf[65536];
138         int res;
139         int ttl = sizeof(struct ast_frame);
140         struct ast_frame *f = (struct ast_frame *)buf;
141         /* Read a frame directly from there.  They're always in the
142            right format. */
143         
144         while(ttl) {
145                 res = read(fd, buf, ttl);
146                 if (res < 0) {
147                         ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
148                         return NULL;
149                 }
150                 ttl -= res;
151         }
152         
153         /* read the frame header */
154         f->mallocd = 0;
155         /* Re-write data position */
156         f->data = buf + sizeof(struct ast_frame);
157         f->offset = 0;
158         /* Forget about being mallocd */
159         f->mallocd = 0;
160         /* Re-write the source */
161         f->src = __FUNCTION__;
162         if (f->datalen > sizeof(buf) - sizeof(struct ast_frame)) {
163                 /* Really bad read */
164                 ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
165                 return NULL;
166         }
167         if (f->datalen) {
168                 if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
169                         /* Bad read */
170                         ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
171                         return NULL;
172                 }
173         }
174         if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
175                 return NULL;
176         }
177         return ast_frisolate(f);
178 }
179
180 /* Some convenient routines for sending frames to/from stream or datagram
181    sockets, pipes, etc (maybe even files) */
182
183 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
184 {
185         /* Write the frame exactly */
186         if (write(fd, frame, sizeof(struct ast_frame)) != sizeof(struct ast_frame)) {
187                 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
188                 return -1;
189         }
190         if (write(fd, frame->data, frame->datalen) != frame->datalen) {
191                 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
192                 return -1;
193         }
194         return 0;
195 }
196
197 int ast_fr_fdhangup(int fd)
198 {
199         struct ast_frame hangup = {
200                 AST_FRAME_CONTROL,
201                 AST_CONTROL_HANGUP
202         };
203         return ast_fr_fdwrite(fd, &hangup);
204 }
205
206 int ast_getformatbyname(char *name)
207 {
208         if (!strcasecmp(name, "g723.1")) 
209                 return AST_FORMAT_G723_1;
210         else if (!strcasecmp(name, "gsm"))
211                 return AST_FORMAT_GSM;
212         else if (!strcasecmp(name, "ulaw"))
213                 return AST_FORMAT_ULAW;
214         else if (!strcasecmp(name, "alaw"))
215                 return AST_FORMAT_ALAW;
216         else if (!strcasecmp(name, "mp3"))
217                 return AST_FORMAT_MP3;
218         else if (!strcasecmp(name, "slinear"))
219                 return AST_FORMAT_SLINEAR;
220         else if (!strcasecmp(name, "lpc10"))
221                 return AST_FORMAT_LPC10;
222         else if (!strcasecmp(name, "adpcm"))
223                 return AST_FORMAT_ADPCM;
224         else if (!strcasecmp(name, "all"))
225                 return 0x7FFFFFFF;
226         return 0;
227 }
228
229 #ifdef TRACE_FRAMES
230 static int show_frame_stats(int fd, int argc, char *argv[])
231 {
232         struct ast_frame *f;
233         int x=1;
234         if (argc != 3)
235                 return RESULT_SHOWUSAGE;
236         ast_cli(fd, "     Framer Statistics     \n");
237         ast_cli(fd, "---------------------------\n");
238         ast_cli(fd, "Total allocated headers: %d\n", headers);
239         ast_cli(fd, "Queue Dump:\n");
240         pthread_mutex_lock(&framelock);
241         for (f=headerlist; f; f = f->next) {
242                 ast_cli(fd, "%d.  Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
243         }
244         pthread_mutex_unlock(&framelock);
245         return RESULT_SUCCESS;
246 }
247
248 static char frame_stats_usage[] =
249 "Usage: show frame stats\n"
250 "       Displays debugging statistics from framer\n";
251
252 struct ast_cli_entry cli_frame_stats =
253 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage };
254 #endif
255
256 int init_framer(void)
257 {
258 #ifdef TRACE_FRAMES
259         ast_cli_register(&cli_frame_stats);
260 #endif
261         return 0;       
262 }