00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 233782 $")
00031
00032 #include <unistd.h>
00033 #include <netinet/in.h>
00034 #include <arpa/inet.h>
00035 #include <stdlib.h>
00036 #include <sys/time.h>
00037 #include <stdio.h>
00038 #include <errno.h>
00039 #include <string.h>
00040
00041 #include "asterisk/lock.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/sched.h"
00046 #include "asterisk/module.h"
00047 #include "asterisk/endian.h"
00048
00049
00050
00051
00052
00053 #define ILBC_BUF_SIZE 50
00054 #define ILBC_SAMPLES 240
00055
00056 static struct ast_frame *ilbc_read(struct ast_filestream *s, int *whennext)
00057 {
00058 int res;
00059
00060 s->fr.frametype = AST_FRAME_VOICE;
00061 s->fr.subclass = AST_FORMAT_ILBC;
00062 s->fr.mallocd = 0;
00063 AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, ILBC_BUF_SIZE);
00064 if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
00065 if (res)
00066 ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
00067 return NULL;
00068 }
00069 *whennext = s->fr.samples = ILBC_SAMPLES;
00070 return &s->fr;
00071 }
00072
00073 static int ilbc_write(struct ast_filestream *fs, struct ast_frame *f)
00074 {
00075 int res;
00076 if (f->frametype != AST_FRAME_VOICE) {
00077 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00078 return -1;
00079 }
00080 if (f->subclass != AST_FORMAT_ILBC) {
00081 ast_log(LOG_WARNING, "Asked to write non-iLBC frame (%d)!\n", f->subclass);
00082 return -1;
00083 }
00084 if (f->datalen % 50) {
00085 ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 50\n", f->datalen);
00086 return -1;
00087 }
00088 if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
00089 ast_log(LOG_WARNING, "Bad write (%d/50): %s\n", res, strerror(errno));
00090 return -1;
00091 }
00092 return 0;
00093 }
00094
00095 static int ilbc_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
00096 {
00097 long bytes;
00098 off_t min,cur,max,offset=0;
00099 min = 0;
00100 cur = ftello(fs->f);
00101 fseeko(fs->f, 0, SEEK_END);
00102 max = ftello(fs->f);
00103
00104 bytes = ILBC_BUF_SIZE * (sample_offset / ILBC_SAMPLES);
00105 if (whence == SEEK_SET)
00106 offset = bytes;
00107 else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
00108 offset = cur + bytes;
00109 else if (whence == SEEK_END)
00110 offset = max - bytes;
00111 if (whence != SEEK_FORCECUR) {
00112 offset = (offset > max)?max:offset;
00113 }
00114
00115 offset = (offset < min)?min:offset;
00116 if (fseeko(fs->f, offset, SEEK_SET) < 0)
00117 return -1;
00118 return 0;
00119 }
00120
00121 static int ilbc_trunc(struct ast_filestream *fs)
00122 {
00123
00124 if (ftruncate(fileno(fs->f), ftello(fs->f)) < 0)
00125 return -1;
00126 return 0;
00127 }
00128
00129 static off_t ilbc_tell(struct ast_filestream *fs)
00130 {
00131 off_t offset = ftello(fs->f);
00132 return (offset/ILBC_BUF_SIZE)*ILBC_SAMPLES;
00133 }
00134
00135 static const struct ast_format ilbc_f = {
00136 .name = "iLBC",
00137 .exts = "ilbc",
00138 .format = AST_FORMAT_ILBC,
00139 .write = ilbc_write,
00140 .seek = ilbc_seek,
00141 .trunc = ilbc_trunc,
00142 .tell = ilbc_tell,
00143 .read = ilbc_read,
00144 .buf_size = ILBC_BUF_SIZE + AST_FRIENDLY_OFFSET,
00145 };
00146
00147 static int load_module(void)
00148 {
00149 return ast_format_register(&ilbc_f);
00150 }
00151
00152 static int unload_module(void)
00153 {
00154 return ast_format_unregister(ilbc_f.name);
00155 }
00156
00157 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Raw iLBC data",
00158 .load = load_module,
00159 .unload = unload_module,
00160 );