Updates from char * to const char * + german syntax + enumeration (bug #2780)
[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                 if (ast_mutex_lock(&g723_lock)) {
59                         ast_log(LOG_WARNING, "Unable to lock g723 list\n");
60                         free(tmp);
61                         return NULL;
62                 }
63                 tmp->fd = fd;
64                 tmp->fr = (struct ast_frame *)tmp->buf;
65                 tmp->fr->data = tmp->buf + sizeof(struct ast_frame);
66                 tmp->fr->frametype = AST_FRAME_VOICE;
67                 tmp->fr->subclass = AST_FORMAT_G723_1;
68                 /* datalen will vary for each frame */
69                 tmp->fr->src = name;
70                 tmp->fr->mallocd = 0;
71                 tmp->lasttimeout = -1;
72                 tmp->orig.tv_usec = 0;
73                 tmp->orig.tv_sec = 0;
74                 glistcnt++;
75                 ast_mutex_unlock(&g723_lock);
76                 ast_update_use_count();
77         }
78         return tmp;
79 }
80
81 static struct ast_filestream *g723_rewrite(int fd, const char *comment)
82 {
83         /* We don't have any header to read or anything really, but
84            if we did, it would go here.  We also might want to check
85            and be sure it's a valid file.  */
86         struct ast_filestream *tmp;
87         if ((tmp = malloc(sizeof(struct ast_filestream)))) {
88                 if (ast_mutex_lock(&g723_lock)) {
89                         ast_log(LOG_WARNING, "Unable to lock g723 list\n");
90                         free(tmp);
91                         return NULL;
92                 }
93                 tmp->fd = fd;
94                 tmp->owner = NULL;
95                 tmp->fr = NULL;
96                 tmp->lasttimeout = -1;
97                 tmp->orig.tv_usec = 0;
98                 tmp->orig.tv_sec = 0;
99                 glistcnt++;
100                 ast_mutex_unlock(&g723_lock);
101                 ast_update_use_count();
102         } else
103                 ast_log(LOG_WARNING, "Out of memory\n");
104         return tmp;
105 }
106
107 static struct ast_frame *g723_read(struct ast_filestream *s)
108 {
109         return NULL;
110 }
111
112 static void g723_close(struct ast_filestream *s)
113 {
114         struct ast_filestream *tmp, *tmpl = NULL;
115         if (ast_mutex_lock(&g723_lock)) {
116                 ast_log(LOG_WARNING, "Unable to lock g723 list\n");
117                 return;
118         }
119         tmp = glist;
120         while(tmp) {
121                 if (tmp == s) {
122                         if (tmpl)
123                                 tmpl->next = tmp->next;
124                         else
125                                 glist = tmp->next;
126                         break;
127                 }
128                 tmpl = tmp;
129                 tmp = tmp->next;
130         }
131         glistcnt--;
132         if (s->owner) {
133                 s->owner->stream = NULL;
134                 if (s->owner->streamid > -1)
135                         ast_sched_del(s->owner->sched, s->owner->streamid);
136                 s->owner->streamid = -1;
137         }
138         ast_mutex_unlock(&g723_lock);
139         ast_update_use_count();
140         if (!tmp) 
141                 ast_log(LOG_WARNING, "Freeing a filestream we don't seem to own\n");
142         close(s->fd);
143         free(s);
144         s = NULL;
145 }
146
147 static int ast_read_callback(void *data)
148 {
149         u_int16_t size;
150         u_int32_t delay = -1;
151         int looper = 1;
152         int retval = 0;
153         int res;
154         struct ast_filestream *s = data;
155         /* Send a frame from the file to the appropriate channel */
156         while(looper) {
157                 if (read(s->fd, &size, 2) != 2) {
158                         /* Out of data, or the file is no longer valid.  In any case
159                            go ahead and stop the stream */
160                         s->owner->streamid = -1;
161                         return 0;
162                 }
163                 /* Looks like we have a frame to read from here */
164                 size = ntohs(size);
165                 if (size > G723_MAX_SIZE - sizeof(struct ast_frame)) {
166                         ast_log(LOG_WARNING, "Size %d is invalid\n", size);
167                         /* The file is apparently no longer any good, as we
168                            shouldn't ever get frames even close to this 
169                            size.  */
170                         s->owner->streamid = -1;
171                         return 0;
172                 }
173                 /* Read the data into the buffer */
174                 s->fr->offset = AST_FRIENDLY_OFFSET;
175                 s->fr->datalen = size;
176                 s->fr->data = s->buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
177                 if ((res = read(s->fd, s->fr->data , size)) != size) {
178                         ast_log(LOG_WARNING, "Short read (%d of %d bytes) (%s)!\n", res, size, strerror(errno));
179                         s->owner->streamid = -1;
180                         return 0;
181                 }
182                 /* Read the delay for the next packet, and schedule again if necessary */
183                 if (read(s->fd, &delay, 4) == 4) 
184                         delay = ntohl(delay);
185                 else
186                         delay = -1;
187 #if 0
188                 /* Average out frames <= 50 ms */
189                 if (delay < 50)
190                         s->fr->timelen = 30;
191                 else
192                         s->fr->timelen = delay;
193 #else
194                 s->fr->samples = 240;
195 #endif
196                 /* Unless there is no delay, we're going to exit out as soon as we
197                    have processed the current frame. */
198                 if (delay > VOFR_FUDGE) {
199                         looper = 0;
200                         /* If there is a delay, lets schedule the next event */
201                         if (delay != s->lasttimeout) {
202                                 /* We'll install the next timeout now. */
203                                 s->owner->streamid = ast_sched_add(s->owner->sched, 
204                                                                                                           delay - VOFR_FUDGE, 
205                                                                                                           ast_read_callback, s);
206                                 
207                                 s->lasttimeout = delay;
208                         } else
209                                 /* Just come back again at the same time */
210                                 retval = -1;
211                 }
212                 /* Lastly, process the frame */
213                 if (ast_write(s->owner, s->fr)) {
214                         ast_log(LOG_WARNING, "Failed to write frame\n");
215                         s->owner->streamid = -1;
216                         return 0;
217                 }
218         }
219         return retval;
220 }
221
222 static int g723_apply(struct ast_channel *c, struct ast_filestream *s)
223 {
224         /* Select our owner for this stream, and get the ball rolling. */
225         s->owner = c;
226         return 0;
227 }
228
229 static int g723_play(struct ast_filestream *s)
230 {
231         u_int32_t delay;
232         /* Read and ignore the first delay */
233         if (read(s->fd, &delay, 4) != 4) {
234                 /* Empty file */
235                 return 0;
236         }
237         ast_read_callback(s);
238         return 0;
239 }
240
241 static int g723_write(struct ast_filestream *fs, struct ast_frame *f)
242 {
243         struct timeval now;
244         u_int32_t delay;
245         u_int16_t size;
246         int res;
247         if (fs->fr) {
248                 ast_log(LOG_WARNING, "Asked to write on a read stream??\n");
249                 return -1;
250         }
251         if (f->frametype != AST_FRAME_VOICE) {
252                 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
253                 return -1;
254         }
255         if (f->subclass != AST_FORMAT_G723_1) {
256                 ast_log(LOG_WARNING, "Asked to write non-g723 frame!\n");
257                 return -1;
258         }
259         if (!(fs->orig.tv_usec || fs->orig.tv_sec)) {
260                 /* First frame should have zeros for delay */
261                 delay = 0;
262                 if (gettimeofday(&fs->orig, NULL)) {
263                         ast_log(LOG_WARNING, "gettimeofday() failed??  What is this?  Y2k?\n");
264                         return -1;
265                 }
266         } else {
267                 if (gettimeofday(&now, NULL)) {
268                         ast_log(LOG_WARNING, "gettimeofday() failed??  What is this?  Y2k?\n");
269                         return -1;
270                 }
271                 delay = (now.tv_sec - fs->orig.tv_sec) * 1000 + (now.tv_usec - fs->orig.tv_usec) / 1000;
272                 delay = htonl(delay);
273                 fs->orig.tv_sec = now.tv_sec;
274                 fs->orig.tv_usec = now.tv_usec;
275         }
276         if (f->datalen <= 0) {
277                 ast_log(LOG_WARNING, "Short frame ignored (%d bytes long?)\n", f->datalen);
278                 return 0;
279         }
280         if ((res = write(fs->fd, &delay, 4)) != 4) {
281                 ast_log(LOG_WARNING, "Unable to write delay: res=%d (%s)\n", res, strerror(errno));
282                 return -1;
283         }
284         size = htons(f->datalen);
285         if ((res =write(fs->fd, &size, 2)) != 2) {
286                 ast_log(LOG_WARNING, "Unable to write size: res=%d (%s)\n", res, strerror(errno));
287                 return -1;
288         }
289         if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
290                 ast_log(LOG_WARNING, "Unable to write frame: res=%d (%s)\n", res, strerror(errno));
291                 return -1;
292         }       
293         return 0;
294 }
295
296 static int g723_seek(struct ast_filestream *fs, long sample_offset, int whence)
297 {
298         return -1;
299 }
300
301 static int g723_trunc(struct ast_filestream *fs)
302 {
303         return -1;
304 }
305
306 static long g723_tell(struct ast_filestream *fs)
307 {
308         return -1;
309 }
310
311 static char *g723_getcomment(struct ast_filestream *s)
312 {
313         return NULL;
314 }
315
316 int load_module()
317 {
318         return ast_format_register(name, exts, AST_FORMAT_G723_1,
319                                                                 g723_open,
320                                                                 g723_rewrite,
321                                                                 g723_apply,
322                                                                 g723_play,
323                                                                 g723_write,
324                                                                 g723_seek,
325                                                                 g723_trunc,
326                                                                 g723_tell,
327                                                                 g723_read,
328                                                                 g723_close,
329                                                                 g723_getcomment);
330                                                                 
331                                                                 
332 }
333
334 int unload_module()
335 {
336         struct ast_filestream *tmp, *tmpl;
337         if (ast_mutex_lock(&g723_lock)) {
338                 ast_log(LOG_WARNING, "Unable to lock g723 list\n");
339                 return -1;
340         }
341         tmp = glist;
342         while(tmp) {
343                 if (tmp->owner)
344                         ast_softhangup(tmp->owner, AST_SOFTHANGUP_APPUNLOAD);
345                 tmpl = tmp;
346                 tmp = tmp->next;
347                 free(tmpl);
348         }
349         ast_mutex_unlock(&g723_lock);
350         return ast_format_unregister(name);
351 }       
352
353 int usecount()
354 {
355         int res;
356         if (ast_mutex_lock(&g723_lock)) {
357                 ast_log(LOG_WARNING, "Unable to lock g723 list\n");
358                 return -1;
359         }
360         res = glistcnt;
361         ast_mutex_unlock(&g723_lock);
362         return res;
363 }
364
365 char *description()
366 {
367         return desc;
368 }
369
370
371 char *key()
372 {
373         return ASTERISK_GPL_KEY;
374 }