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

« back to all changes in this revision

Viewing changes to formats/format_gsm.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
 * Save to raw, headerless GSM data.
 
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 <sys/time.h>
 
22
#include <stdio.h>
 
23
#include <unistd.h>
 
24
#include <errno.h>
 
25
#include <string.h>
 
26
#include <pthread.h>
 
27
#include <endian.h>
 
28
 
 
29
/* Some Ideas for this code came from makegsme.c by Jeffery Chilton */
 
30
 
 
31
/* Portions of the conversion code are by guido@sienanet.it */
 
32
 
 
33
struct ast_filestream {
 
34
        void *reserved[AST_RESERVED_POINTERS];
 
35
        /* Believe it or not, we must decode/recode to account for the
 
36
           weird MS format */
 
37
        /* This is what a filestream means to us */
 
38
        int fd; /* Descriptor */
 
39
        struct ast_channel *owner;
 
40
        struct ast_frame fr;                            /* Frame information */
 
41
        char waste[AST_FRIENDLY_OFFSET];        /* Buffer for sending frames, etc */
 
42
        char empty;                                                     /* Empty character */
 
43
        unsigned char gsm[33];                          /* Two Real GSM Frames */
 
44
        int lasttimeout;
 
45
        struct timeval last;
 
46
        int adj;
 
47
        struct ast_filestream *next;
 
48
};
 
49
 
 
50
 
 
51
static struct ast_filestream *glist = NULL;
 
52
static pthread_mutex_t gsm_lock = PTHREAD_MUTEX_INITIALIZER;
 
53
static int glistcnt = 0;
 
54
 
 
55
static char *name = "gsm";
 
56
static char *desc = "Raw GSM data";
 
57
static char *exts = "gsm";
 
58
 
 
59
static struct ast_filestream *gsm_open(int fd)
 
60
{
 
61
        /* We don't have any header to read or anything really, but
 
62
           if we did, it would go here.  We also might want to check
 
63
           and be sure it's a valid file.  */
 
64
        struct ast_filestream *tmp;
 
65
        if ((tmp = malloc(sizeof(struct ast_filestream)))) {
 
66
                memset(tmp, 0, sizeof(struct ast_filestream));
 
67
                if (ast_pthread_mutex_lock(&gsm_lock)) {
 
68
                        ast_log(LOG_WARNING, "Unable to lock gsm list\n");
 
69
                        free(tmp);
 
70
                        return NULL;
 
71
                }
 
72
                tmp->next = glist;
 
73
                glist = tmp;
 
74
                tmp->fd = fd;
 
75
                tmp->owner = NULL;
 
76
                tmp->fr.data = tmp->gsm;
 
77
                tmp->fr.frametype = AST_FRAME_VOICE;
 
78
                tmp->fr.subclass = AST_FORMAT_GSM;
 
79
                /* datalen will vary for each frame */
 
80
                tmp->fr.src = name;
 
81
                tmp->fr.mallocd = 0;
 
82
                tmp->lasttimeout = -1;
 
83
                glistcnt++;
 
84
                ast_pthread_mutex_unlock(&gsm_lock);
 
85
                ast_update_use_count();
 
86
        }
 
87
        return tmp;
 
88
}
 
89
 
 
90
static struct ast_filestream *gsm_rewrite(int fd, char *comment)
 
91
{
 
92
        /* We don't have any header to read or anything really, but
 
93
           if we did, it would go here.  We also might want to check
 
94
           and be sure it's a valid file.  */
 
95
        struct ast_filestream *tmp;
 
96
        if ((tmp = malloc(sizeof(struct ast_filestream)))) {
 
97
                memset(tmp, 0, sizeof(struct ast_filestream));
 
98
                if (ast_pthread_mutex_lock(&gsm_lock)) {
 
99
                        ast_log(LOG_WARNING, "Unable to lock gsm list\n");
 
100
                        free(tmp);
 
101
                        return NULL;
 
102
                }
 
103
                tmp->next = glist;
 
104
                glist = tmp;
 
105
                tmp->fd = fd;
 
106
                tmp->owner = NULL;
 
107
                tmp->lasttimeout = -1;
 
108
                glistcnt++;
 
109
                ast_pthread_mutex_unlock(&gsm_lock);
 
110
                ast_update_use_count();
 
111
        } else
 
112
                ast_log(LOG_WARNING, "Out of memory\n");
 
113
        return tmp;
 
114
}
 
115
 
 
116
static struct ast_frame *gsm_read(struct ast_filestream *s)
 
117
{
 
118
        return NULL;
 
119
}
 
120
 
 
121
static void gsm_close(struct ast_filestream *s)
 
122
{
 
123
        struct ast_filestream *tmp, *tmpl = NULL;
 
124
        if (ast_pthread_mutex_lock(&gsm_lock)) {
 
125
                ast_log(LOG_WARNING, "Unable to lock gsm list\n");
 
126
                return;
 
127
        }
 
128
        tmp = glist;
 
129
        while(tmp) {
 
130
                if (tmp == s) {
 
131
                        if (tmpl)
 
132
                                tmpl->next = tmp->next;
 
133
                        else
 
134
                                glist = tmp->next;
 
135
                        break;
 
136
                }
 
137
                tmpl = tmp;
 
138
                tmp = tmp->next;
 
139
        }
 
140
        glistcnt--;
 
141
        if (s->owner) {
 
142
                s->owner->stream = NULL;
 
143
                if (s->owner->streamid > -1)
 
144
                        ast_sched_del(s->owner->sched, s->owner->streamid);
 
145
                s->owner->streamid = -1;
 
146
        }
 
147
        ast_pthread_mutex_unlock(&gsm_lock);
 
148
        ast_update_use_count();
 
149
        if (!tmp) 
 
150
                ast_log(LOG_WARNING, "Freeing a filestream we don't seem to own\n");
 
151
        close(s->fd);
 
152
        free(s);
 
153
}
 
154
 
 
155
static int ast_read_callback(void *data)
 
156
{
 
157
        int retval = 0;
 
158
        int res;
 
159
        int delay = 20;
 
160
        struct ast_filestream *s = data;
 
161
        struct timeval tv;
 
162
        /* Send a frame from the file to the appropriate channel */
 
163
 
 
164
        s->fr.frametype = AST_FRAME_VOICE;
 
165
        s->fr.subclass = AST_FORMAT_GSM;
 
166
        s->fr.offset = AST_FRIENDLY_OFFSET;
 
167
        s->fr.timelen = 20;
 
168
        s->fr.datalen = 33;
 
169
        s->fr.mallocd = 0;
 
170
        s->fr.data = s->gsm;
 
171
        if ((res = read(s->fd, s->gsm, 33)) != 33) {
 
172
                if (res)
 
173
                        ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
 
174
                s->owner->streamid = -1;
 
175
                return 0;
 
176
        }
 
177
        /* Lastly, process the frame */
 
178
        if (ast_write(s->owner, &s->fr)) {
 
179
                ast_log(LOG_WARNING, "Failed to write frame\n");
 
180
                s->owner->streamid = -1;
 
181
                return 0;
 
182
        }
 
183
        if (s->last.tv_usec || s->last.tv_usec) {
 
184
                int ms;
 
185
                gettimeofday(&tv, NULL);
 
186
                ms = 1000 * (tv.tv_sec - s->last.tv_sec) + 
 
187
                        (tv.tv_usec - s->last.tv_usec) / 1000;
 
188
                s->last.tv_sec = tv.tv_sec;
 
189
                s->last.tv_usec = tv.tv_usec;
 
190
                if ((ms - delay) * (ms - delay) > 4) {
 
191
                        /* Compensate if we're more than 2 ms off */
 
192
                        s->adj -= (ms - delay);
 
193
                }
 
194
#if 0
 
195
                fprintf(stdout, "Delay is %d, adjustment is %d, last was %d\n", delay, s->adj, ms);
 
196
#endif
 
197
                delay += s->adj;
 
198
                if (delay < 1)
 
199
                        delay = 1;
 
200
        } else
 
201
                gettimeofday(&s->last, NULL);
 
202
        if (s->lasttimeout != delay) {
 
203
                /* We'll install the next timeout now. */
 
204
                s->owner->streamid = ast_sched_add(s->owner->sched,
 
205
                                delay, ast_read_callback, s); 
 
206
                s->lasttimeout = delay;
 
207
        } else {
 
208
                /* Just come back again at the same time */
 
209
                retval = -1;
 
210
        }
 
211
        return retval;
 
212
}
 
213
 
 
214
static int gsm_apply(struct ast_channel *c, struct ast_filestream *s)
 
215
{
 
216
        /* Select our owner for this stream, and get the ball rolling. */
 
217
        s->owner = c;
 
218
        ast_read_callback(s);
 
219
        return 0;
 
220
}
 
221
 
 
222
static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
 
223
{
 
224
        int res;
 
225
        if (f->frametype != AST_FRAME_VOICE) {
 
226
                ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
 
227
                return -1;
 
228
        }
 
229
        if (f->subclass != AST_FORMAT_GSM) {
 
230
                ast_log(LOG_WARNING, "Asked to write non-GSM frame (%d)!\n", f->subclass);
 
231
                return -1;
 
232
        }
 
233
        if (f->datalen % 33) {
 
234
                ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 33\n", f->datalen);
 
235
                return -1;
 
236
        }
 
237
        if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
 
238
                        ast_log(LOG_WARNING, "Bad write (%d/33): %s\n", res, strerror(errno));
 
239
                        return -1;
 
240
        }
 
241
        return 0;
 
242
}
 
243
 
 
244
static char *gsm_getcomment(struct ast_filestream *s)
 
245
{
 
246
        return NULL;
 
247
}
 
248
 
 
249
int load_module()
 
250
{
 
251
        return ast_format_register(name, exts, AST_FORMAT_GSM,
 
252
                                                                gsm_open,
 
253
                                                                gsm_rewrite,
 
254
                                                                gsm_apply,
 
255
                                                                gsm_write,
 
256
                                                                gsm_read,
 
257
                                                                gsm_close,
 
258
                                                                gsm_getcomment);
 
259
                                                                
 
260
                                                                
 
261
}
 
262
 
 
263
int unload_module()
 
264
{
 
265
        struct ast_filestream *tmp, *tmpl;
 
266
        if (ast_pthread_mutex_lock(&gsm_lock)) {
 
267
                ast_log(LOG_WARNING, "Unable to lock gsm list\n");
 
268
                return -1;
 
269
        }
 
270
        tmp = glist;
 
271
        while(tmp) {
 
272
                if (tmp->owner)
 
273
                        ast_softhangup(tmp->owner);
 
274
                tmpl = tmp;
 
275
                tmp = tmp->next;
 
276
                free(tmpl);
 
277
        }
 
278
        ast_pthread_mutex_unlock(&gsm_lock);
 
279
        return ast_format_unregister(name);
 
280
}       
 
281
 
 
282
int usecount()
 
283
{
 
284
        int res;
 
285
        if (ast_pthread_mutex_lock(&gsm_lock)) {
 
286
                ast_log(LOG_WARNING, "Unable to lock gsm list\n");
 
287
                return -1;
 
288
        }
 
289
        res = glistcnt;
 
290
        ast_pthread_mutex_unlock(&gsm_lock);
 
291
        return res;
 
292
}
 
293
 
 
294
char *description()
 
295
{
 
296
        return desc;
 
297
}
 
298
 
 
299
 
 
300
char *key()
 
301
{
 
302
        return ASTERISK_GPL_KEY;
 
303
}