Version 0.1.7 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
21 /*
22  * Important: I should be made more efficient.  Frame headers should
23  * most definitely be cached
24  */
25
26 void ast_frfree(struct ast_frame *fr)
27 {
28         if (fr->mallocd & AST_MALLOCD_DATA) {
29                 if (fr->data) 
30                         free(fr->data - fr->offset);
31         }
32         if (fr->mallocd & AST_MALLOCD_SRC) {
33                 if (fr->src)
34                         free(fr->src);
35         }
36         if (fr->mallocd & AST_MALLOCD_HDR) {
37                 free(fr);
38         }
39 }
40
41 void ast_frchain(struct ast_frame_chain *fc)
42 {
43         struct ast_frame_chain *last;
44         while(fc) {
45                 last = fc;
46                 fc = fc->next;
47                 if (last->fr)
48                         ast_frfree(last->fr);
49                 free(last);
50         }
51 }
52
53 struct ast_frame *ast_frisolate(struct ast_frame *fr)
54 {
55         struct ast_frame *out;
56         if (!(fr->mallocd & AST_MALLOCD_HDR)) {
57                 /* Allocate a new header if needed */
58                 out = malloc(sizeof(struct ast_frame));
59                 if (!out) {
60                         ast_log(LOG_WARNING, "Out of memory\n");
61                         return NULL;
62                 }
63                 out->frametype = fr->frametype;
64                 out->subclass = fr->subclass;
65                 out->datalen = 0;
66                 out->timelen = fr->timelen;
67                 out->offset = 0;
68                 out->src = NULL;
69                 out->data = NULL;
70         } else {
71                 out = fr;
72         }
73         if (!(fr->mallocd & AST_MALLOCD_SRC)) {
74                 if (fr->src)
75                         out->src = strdup(fr->src);
76         } else
77                 out->src = fr->src;
78         if (!(fr->mallocd & AST_MALLOCD_DATA))  {
79                 out->data = malloc(fr->datalen + AST_FRIENDLY_OFFSET);
80                 if (!out->data) {
81                         free(out);
82                         ast_log(LOG_WARNING, "Out of memory\n");
83                         return NULL;
84                 }
85                 out->data += AST_FRIENDLY_OFFSET;
86                 out->offset = AST_FRIENDLY_OFFSET;
87                 out->datalen = fr->datalen;
88                 memcpy(out->data, fr->data, fr->datalen);
89         }
90         out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
91         return out;
92 }
93
94 struct ast_frame *ast_frdup(struct ast_frame *f)
95 {
96         struct ast_frame *ret;
97         int p;
98         p = f->mallocd;
99         f->mallocd = 0;
100         /* Make frisolate think this is a 100% static frame, and make a duplicate */
101         ret = ast_frisolate(f);
102         /* Restore its true malloc status */
103         f->mallocd = p;
104         return ret;
105 }
106
107 struct ast_frame *ast_fr_fdread(int fd)
108 {
109         char buf[4096];
110         int res;
111         struct ast_frame *f = (struct ast_frame *)buf;
112         /* Read a frame directly from there.  They're always in the
113            right format. */
114         
115         if (read(fd, buf, sizeof(struct ast_frame)) 
116                                                 == sizeof(struct ast_frame)) {
117                 /* read the frame header */
118                 f->mallocd = 0;
119                 /* Re-write data position */
120                 f->data = buf + sizeof(struct ast_frame);
121                 f->offset = 0;
122                 /* Forget about being mallocd */
123                 f->mallocd = 0;
124                 /* Re-write the source */
125                 f->src = __FUNCTION__;
126                 if (f->datalen > sizeof(buf) - sizeof(struct ast_frame)) {
127                         /* Really bad read */
128                         ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
129                         return NULL;
130                 }
131                 if (f->datalen) {
132                         if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
133                                 /* Bad read */
134                                 ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
135                                 return NULL;
136                         }
137                 }
138                 return ast_frisolate(f);
139         } else if (option_debug)
140                 ast_log(LOG_DEBUG, "NULL or invalid header\n");
141         /* Null if there was an error */
142         return NULL;
143 }
144
145 /* Some convenient routines for sending frames to/from stream or datagram
146    sockets, pipes, etc (maybe even files) */
147
148 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
149 {
150         /* Write the frame exactly */
151         if (write(fd, frame, sizeof(struct ast_frame)) != sizeof(struct ast_frame)) {
152                 ast_log(LOG_WARNING, "Write error\n");
153                 return -1;
154         }
155         if (write(fd, frame->data, frame->datalen) != frame->datalen) {
156                 ast_log(LOG_WARNING, "Write error\n");
157                 return -1;
158         }
159         return 0;
160 }
161
162 int ast_getformatbyname(char *name)
163 {
164         if (!strcasecmp(name, "g723.1")) 
165                 return AST_FORMAT_G723_1;
166         else if (!strcasecmp(name, "gsm"))
167                 return AST_FORMAT_GSM;
168         else if (!strcasecmp(name, "ulaw"))
169                 return AST_FORMAT_ULAW;
170         else if (!strcasecmp(name, "alaw"))
171                 return AST_FORMAT_ALAW;
172         else if (!strcasecmp(name, "mp3"))
173                 return AST_FORMAT_MP3;
174         else if (!strcasecmp(name, "slinear"))
175                 return AST_FORMAT_SLINEAR;
176         else if (!strcasecmp(name, "lpc10"))
177                 return AST_FORMAT_LPC10;
178         else if (!strcasecmp(name, "adpcm"))
179                 return AST_FORMAT_ADPCM;
180         else if (!strcasecmp(name, "all"))
181                 return 0x7FFFFFFF;
182         return 0;
183 }