2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Save to raw, headerless GSM data.
22 * \arg File name extension: gsm
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
37 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39 #include "asterisk/lock.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/file.h"
42 #include "asterisk/logger.h"
43 #include "asterisk/sched.h"
44 #include "asterisk/module.h"
45 #include "asterisk/endian.h"
49 /* Some Ideas for this code came from makegsme.c by Jeffrey Chilton */
51 /* Portions of the conversion code are by guido@sienanet.it */
53 /* silent gsm frame */
54 /* begin binary data: */
55 char gsm_silence[] = /* 33 */
56 {0xD8,0x20,0xA2,0xE1,0x5A,0x50,0x00,0x49,0x24,0x92,0x49,0x24,0x50,0x00,0x49
57 ,0x24,0x92,0x49,0x24,0x50,0x00,0x49,0x24,0x92,0x49,0x24,0x50,0x00,0x49,0x24
59 /* end binary data. size = 33 bytes */
61 struct ast_filestream {
62 void *reserved[AST_RESERVED_POINTERS];
63 /* Believe it or not, we must decode/recode to account for the
65 /* This is what a filestream means to us */
66 FILE *f; /* Descriptor */
67 struct ast_frame fr; /* Frame information */
68 char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
69 char empty; /* Empty character */
70 unsigned char gsm[66]; /* Two Real GSM Frames */
74 AST_MUTEX_DEFINE_STATIC(gsm_lock);
75 static int glistcnt = 0;
77 static char *name = "gsm";
78 static char *desc = "Raw GSM data";
79 static char *exts = "gsm";
81 static struct ast_filestream *gsm_open(FILE *f)
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 memset(tmp, 0, sizeof(struct ast_filestream));
89 if (ast_mutex_lock(&gsm_lock)) {
90 ast_log(LOG_WARNING, "Unable to lock gsm list\n");
95 tmp->fr.data = tmp->gsm;
96 tmp->fr.frametype = AST_FRAME_VOICE;
97 tmp->fr.subclass = AST_FORMAT_GSM;
98 /* datalen will vary for each frame */
102 ast_mutex_unlock(&gsm_lock);
103 ast_update_use_count();
108 static struct ast_filestream *gsm_rewrite(FILE *f, const char *comment)
110 /* We don't have any header to read or anything really, but
111 if we did, it would go here. We also might want to check
112 and be sure it's a valid file. */
113 struct ast_filestream *tmp;
114 if ((tmp = malloc(sizeof(struct ast_filestream)))) {
115 memset(tmp, 0, sizeof(struct ast_filestream));
116 if (ast_mutex_lock(&gsm_lock)) {
117 ast_log(LOG_WARNING, "Unable to lock gsm list\n");
123 ast_mutex_unlock(&gsm_lock);
124 ast_update_use_count();
126 ast_log(LOG_WARNING, "Out of memory\n");
130 static void gsm_close(struct ast_filestream *s)
132 if (ast_mutex_lock(&gsm_lock)) {
133 ast_log(LOG_WARNING, "Unable to lock gsm list\n");
137 ast_mutex_unlock(&gsm_lock);
138 ast_update_use_count();
143 static struct ast_frame *gsm_read(struct ast_filestream *s, int *whennext)
146 s->fr.frametype = AST_FRAME_VOICE;
147 s->fr.subclass = AST_FORMAT_GSM;
148 s->fr.offset = AST_FRIENDLY_OFFSET;
153 if ((res = fread(s->gsm, 1, 33, s->f)) != 33) {
155 ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
162 static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
165 unsigned char gsm[66];
166 if (f->frametype != AST_FRAME_VOICE) {
167 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
170 if (f->subclass != AST_FORMAT_GSM) {
171 ast_log(LOG_WARNING, "Asked to write non-GSM frame (%d)!\n", f->subclass);
174 if (!(f->datalen % 65)) {
175 /* This is in MSGSM format, need to be converted */
177 while(len < f->datalen) {
178 conv65(f->data + len, gsm);
179 if ((res = fwrite(gsm, 1, 66, fs->f)) != 66) {
180 ast_log(LOG_WARNING, "Bad write (%d/66): %s\n", res, strerror(errno));
186 if (f->datalen % 33) {
187 ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 33\n", f->datalen);
190 if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
191 ast_log(LOG_WARNING, "Bad write (%d/33): %s\n", res, strerror(errno));
198 static int gsm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
200 off_t offset=0,min,cur,max,distance;
204 fseeko(fs->f, 0, SEEK_END);
206 /* have to fudge to frame here, so not fully to sample */
207 distance = (sample_offset/160) * 33;
208 if(whence == SEEK_SET)
210 else if(whence == SEEK_CUR || whence == SEEK_FORCECUR)
211 offset = distance + cur;
212 else if(whence == SEEK_END)
213 offset = max - distance;
214 /* Always protect against seeking past the begining. */
215 offset = (offset < min)?min:offset;
216 if (whence != SEEK_FORCECUR) {
217 offset = (offset > max)?max:offset;
218 } else if (offset > max) {
220 fseeko(fs->f, 0, SEEK_END);
221 for (i=0; i< (offset - max) / 33; i++) {
222 fwrite(gsm_silence, 1, 33, fs->f);
225 return fseeko(fs->f, offset, SEEK_SET);
228 static int gsm_trunc(struct ast_filestream *fs)
230 return ftruncate(fileno(fs->f), ftello(fs->f));
233 static off_t gsm_tell(struct ast_filestream *fs)
236 offset = ftello(fs->f);
237 return (offset/33)*160;
240 static char *gsm_getcomment(struct ast_filestream *s)
247 return ast_format_register(name, exts, AST_FORMAT_GSM,
263 return ast_format_unregister(name);
279 return ASTERISK_GPL_KEY;