Fix compiler warnings (bug #3367)
[asterisk/asterisk.git] / formats / format_g723.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Old-style G.723 frame/timestamp format.
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/lock.h>
15 #include <asterisk/channel.h>
16 #include <asterisk/file.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/sched.h>
19 #include <asterisk/module.h>
20 #include <arpa/inet.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <sys/time.h>
27 #include "../channels/adtranvofr.h"
28
29
30 #define G723_MAX_SIZE 1024
31
32 struct ast_filestream {
33         /* First entry MUST be reserved for the channel type */
34         void *reserved[AST_RESERVED_POINTERS];
35         /* This is what a filestream means to us */
36         int fd; /* Descriptor */
37         struct ast_filestream *next;
38         struct ast_frame *fr;   /* Frame representation of buf */
39         struct timeval orig;    /* Original frame time */
40         char buf[G723_MAX_SIZE + AST_FRIENDLY_OFFSET];  /* Buffer for sending frames, etc */
41 };
42
43
44 AST_MUTEX_DEFINE_STATIC(g723_lock);
45 static int glistcnt = 0;
46
47 static char *name = "g723sf";
48 static char *desc = "G.723.1 Simple Timestamp File Format";
49 static char *exts = "g723|g723sf";
50
51 static struct ast_filestream *g723_open(int fd)
52 {
53         /* We don't have any header to read or anything really, but
54            if we did, it would go here.  We also might want to check
55            and be sure it's a valid file.  */
56         struct ast_filestream *tmp;
57         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
58                 memset(tmp, 0, sizeof(struct ast_filestream));
59                 if (ast_mutex_lock(&g723_lock)) {
60                         ast_log(LOG_WARNING, "Unable to lock g723 list\n");
61                         free(tmp);
62                         return NULL;
63                 }
64                 tmp->fd = fd;
65                 tmp->fr = (struct ast_frame *)tmp->buf;
66                 tmp->fr->data = tmp->buf + sizeof(struct ast_frame);
67                 tmp->fr->frametype = AST_FRAME_VOICE;
68                 tmp->fr->subclass = AST_FORMAT_G723_1;
69                 /* datalen will vary for each frame */
70                 tmp->fr->src = name;
71                 tmp->fr->mallocd = 0;
72                 glistcnt++;
73                 ast_mutex_unlock(&g723_lock);
74                 ast_update_use_count();
75         }
76         return tmp;
77 }
78
79 static struct ast_filestream *g723_rewrite(int fd, const char *comment)
80 {
81         /* We don't have any header to read or anything really, but
82            if we did, it would go here.  We also might want to check
83            and be sure it's a valid file.  */
84         struct ast_filestream *tmp;
85         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
86                 memset(tmp, 0, sizeof(struct ast_filestream));
87                 if (ast_mutex_lock(&g723_lock)) {
88                         ast_log(LOG_WARNING, "Unable to lock g723 list\n");
89                         free(tmp);
90                         return NULL;
91                 }
92                 tmp->fd = fd;
93                 glistcnt++;
94                 ast_mutex_unlock(&g723_lock);
95                 ast_update_use_count();
96         } else
97                 ast_log(LOG_WARNING, "Out of memory\n");
98         return tmp;
99 }
100
101 static struct ast_frame *g723_read(struct ast_filestream *s, int *whennext)
102 {
103         unsigned short size;
104         int res;
105         int delay;
106         /* Read the delay for the next packet, and schedule again if necessary */
107         if (read(s->fd, &delay, 4) == 4) 
108                 delay = ntohl(delay);
109         else
110                 delay = -1;
111         if (read(s->fd, &size, 2) != 2) {
112                 /* Out of data, or the file is no longer valid.  In any case
113                    go ahead and stop the stream */
114                 return NULL;
115         }
116         /* Looks like we have a frame to read from here */
117         size = ntohs(size);
118         if (size > G723_MAX_SIZE - sizeof(struct ast_frame)) {
119                 ast_log(LOG_WARNING, "Size %d is invalid\n", size);
120                 /* The file is apparently no longer any good, as we
121                    shouldn't ever get frames even close to this 
122                    size.  */
123                 return NULL;
124         }
125         /* Read the data into the buffer */
126         s->fr->offset = AST_FRIENDLY_OFFSET;
127         s->fr->datalen = size;
128         s->fr->data = s->buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
129         if ((res = read(s->fd, s->fr->data , size)) != size) {
130                 ast_log(LOG_WARNING, "Short read (%d of %d bytes) (%s)!\n", res, size, strerror(errno));
131                 return NULL;
132         }
133 #if 0
134                 /* Average out frames <= 50 ms */
135                 if (delay < 50)
136                         s->fr->timelen = 30;
137                 else
138                         s->fr->timelen = delay;
139 #else
140                 s->fr->samples = 240;
141 #endif
142         *whennext = s->fr->samples;
143         return s->fr;
144 }
145
146 static void g723_close(struct ast_filestream *s)
147 {
148         if (ast_mutex_lock(&g723_lock)) {
149                 ast_log(LOG_WARNING, "Unable to lock g723 list\n");
150                 return;
151         }
152         glistcnt--;
153         ast_mutex_unlock(&g723_lock);
154         ast_update_use_count();
155         close(s->fd);
156         free(s);
157         s = NULL;
158 }
159
160
161 static int g723_write(struct ast_filestream *fs, struct ast_frame *f)
162 {
163         u_int32_t delay;
164         u_int16_t size;
165         int res;
166         if (fs->fr) {
167                 ast_log(LOG_WARNING, "Asked to write on a read stream??\n");
168                 return -1;
169         }
170         if (f->frametype != AST_FRAME_VOICE) {
171                 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
172                 return -1;
173         }
174         if (f->subclass != AST_FORMAT_G723_1) {
175                 ast_log(LOG_WARNING, "Asked to write non-g723 frame!\n");
176                 return -1;
177         }
178         delay = 0;
179         if (f->datalen <= 0) {
180                 ast_log(LOG_WARNING, "Short frame ignored (%d bytes long?)\n", f->datalen);
181                 return 0;
182         }
183         if ((res = write(fs->fd, &delay, 4)) != 4) {
184                 ast_log(LOG_WARNING, "Unable to write delay: res=%d (%s)\n", res, strerror(errno));
185                 return -1;
186         }
187         size = htons(f->datalen);
188         if ((res =write(fs->fd, &size, 2)) != 2) {
189                 ast_log(LOG_WARNING, "Unable to write size: res=%d (%s)\n", res, strerror(errno));
190                 return -1;
191         }
192         if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
193                 ast_log(LOG_WARNING, "Unable to write frame: res=%d (%s)\n", res, strerror(errno));
194                 return -1;
195         }       
196         return 0;
197 }
198
199 static int g723_seek(struct ast_filestream *fs, long sample_offset, int whence)
200 {
201         return -1;
202 }
203
204 static int g723_trunc(struct ast_filestream *fs)
205 {
206         /* Truncate file to current length */
207         if (ftruncate(fs->fd, lseek(fs->fd, 0, SEEK_CUR)) < 0)
208                 return -1;
209         return 0;
210 }
211
212 static long g723_tell(struct ast_filestream *fs)
213 {
214         return -1;
215 }
216
217 static char *g723_getcomment(struct ast_filestream *s)
218 {
219         return NULL;
220 }
221
222 int load_module()
223 {
224         return ast_format_register(name, exts, AST_FORMAT_G723_1,
225                                                                 g723_open,
226                                                                 g723_rewrite,
227                                                                 g723_write,
228                                                                 g723_seek,
229                                                                 g723_trunc,
230                                                                 g723_tell,
231                                                                 g723_read,
232                                                                 g723_close,
233                                                                 g723_getcomment);
234                                                                 
235                                                                 
236 }
237
238 int unload_module()
239 {
240         return ast_format_unregister(name);
241 }       
242
243 int usecount()
244 {
245         int res;
246         if (ast_mutex_lock(&g723_lock)) {
247                 ast_log(LOG_WARNING, "Unable to lock g723 list\n");
248                 return -1;
249         }
250         res = glistcnt;
251         ast_mutex_unlock(&g723_lock);
252         return res;
253 }
254
255 char *description()
256 {
257         return desc;
258 }
259
260
261 char *key()
262 {
263         return ASTERISK_GPL_KEY;
264 }