2 * Asterisk -- A telephony toolkit for Linux.
4 * Save to raw, headerless G729 data.
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
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 <netinet/in.h>
21 #include <arpa/inet.h>
32 #include "solaris-compat/compat.h"
34 #include <machine/endian.h>
38 /* Some Ideas for this code came from makeg729e.c by Jeffrey Chilton */
40 /* Portions of the conversion code are by guido@sienanet.it */
42 struct ast_filestream {
43 void *reserved[AST_RESERVED_POINTERS];
44 /* Believe it or not, we must decode/recode to account for the
46 /* This is what a filestream means to us */
47 int fd; /* Descriptor */
48 struct ast_frame fr; /* Frame information */
49 char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
50 char empty; /* Empty character */
51 unsigned char g729[20]; /* Two Real G729 Frames */
55 AST_MUTEX_DEFINE_STATIC(g729_lock);
56 static int glistcnt = 0;
58 static char *name = "g729";
59 static char *desc = "Raw G729 data";
60 static char *exts = "g729";
62 static struct ast_filestream *g729_open(int fd)
64 /* We don't have any header to read or anything really, but
65 if we did, it would go here. We also might want to check
66 and be sure it's a valid file. */
67 struct ast_filestream *tmp;
68 if ((tmp = malloc(sizeof(struct ast_filestream)))) {
69 memset(tmp, 0, sizeof(struct ast_filestream));
70 if (ast_mutex_lock(&g729_lock)) {
71 ast_log(LOG_WARNING, "Unable to lock g729 list\n");
76 tmp->fr.data = tmp->g729;
77 tmp->fr.frametype = AST_FRAME_VOICE;
78 tmp->fr.subclass = AST_FORMAT_G729A;
79 /* datalen will vary for each frame */
83 ast_mutex_unlock(&g729_lock);
84 ast_update_use_count();
89 static struct ast_filestream *g729_rewrite(int fd, const char *comment)
91 /* We don't have any header to read or anything really, but
92 if we did, it would go here. We also might want to check
93 and be sure it's a valid file. */
94 struct ast_filestream *tmp;
95 if ((tmp = malloc(sizeof(struct ast_filestream)))) {
96 memset(tmp, 0, sizeof(struct ast_filestream));
97 if (ast_mutex_lock(&g729_lock)) {
98 ast_log(LOG_WARNING, "Unable to lock g729 list\n");
104 ast_mutex_unlock(&g729_lock);
105 ast_update_use_count();
107 ast_log(LOG_WARNING, "Out of memory\n");
111 static void g729_close(struct ast_filestream *s)
113 if (ast_mutex_lock(&g729_lock)) {
114 ast_log(LOG_WARNING, "Unable to lock g729 list\n");
118 ast_mutex_unlock(&g729_lock);
119 ast_update_use_count();
125 static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext)
128 /* Send a frame from the file to the appropriate channel */
129 s->fr.frametype = AST_FRAME_VOICE;
130 s->fr.subclass = AST_FORMAT_G729A;
131 s->fr.offset = AST_FRIENDLY_OFFSET;
135 s->fr.data = s->g729;
136 if ((res = read(s->fd, s->g729, 20)) != 20) {
138 ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
141 *whennext = s->fr.samples;
145 static int g729_write(struct ast_filestream *fs, struct ast_frame *f)
148 if (f->frametype != AST_FRAME_VOICE) {
149 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
152 if (f->subclass != AST_FORMAT_G729A) {
153 ast_log(LOG_WARNING, "Asked to write non-G729 frame (%d)!\n", f->subclass);
156 if (f->datalen % 10) {
157 ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 10\n", f->datalen);
160 if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
161 ast_log(LOG_WARNING, "Bad write (%d/10): %s\n", res, strerror(errno));
167 static char *g729_getcomment(struct ast_filestream *s)
172 static int g729_seek(struct ast_filestream *fs, long sample_offset, int whence)
175 off_t min,cur,max,offset=0;
177 cur = lseek(fs->fd, 0, SEEK_CUR);
178 max = lseek(fs->fd, 0, SEEK_END);
180 bytes = 20 * (sample_offset / 160);
181 if (whence == SEEK_SET)
183 else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
184 offset = cur + bytes;
185 else if (whence == SEEK_END)
186 offset = max - bytes;
187 if (whence != SEEK_FORCECUR) {
188 offset = (offset > max)?max:offset;
190 /* protect against seeking beyond begining. */
191 offset = (offset < min)?min:offset;
192 if (lseek(fs->fd, offset, SEEK_SET) < 0)
197 static int g729_trunc(struct ast_filestream *fs)
199 /* Truncate file to current length */
200 if (ftruncate(fs->fd, lseek(fs->fd, 0, SEEK_CUR)) < 0)
205 static long g729_tell(struct ast_filestream *fs)
208 offset = lseek(fs->fd, 0, SEEK_CUR);
209 return (offset/20)*160;
214 return ast_format_register(name, exts, AST_FORMAT_G729A,
230 return ast_format_unregister(name);
236 if (ast_mutex_lock(&g729_lock)) {
237 ast_log(LOG_WARNING, "Unable to lock g729 list\n");
241 ast_mutex_unlock(&g729_lock);
253 return ASTERISK_GPL_KEY;