~ubuntu-branches/ubuntu/karmic/asterisk/karmic

« back to all changes in this revision

Viewing changes to formats/format_g723.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2002-04-27 21:19:32 UTC
  • Revision ID: james.westby@ubuntu.com-20020427211932-kqaertc4bg7ss5mc
Tags: upstream-0.1.11
ImportĀ upstreamĀ versionĀ 0.1.11

Show diffs side-by-side

added added

removed removed

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