Sat Aug 6 00:39:28 2011

Asterisk developer's documentation


format_g726.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (c) 2004 - 2005, inAccess Networks
00005  *
00006  * Michael Manousos <manousos@inaccessnetworks.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!\file
00020  *
00021  * \brief Headerless G.726 (16/24/32/40kbps) data format for Asterisk.
00022  * 
00023  * File name extensions:
00024  * \arg 40 kbps: g726-40
00025  * \arg 32 kbps: g726-32
00026  * \arg 24 kbps: g726-24
00027  * \arg 16 kbps: g726-16
00028  * \ingroup formats
00029  */
00030  
00031 #include "asterisk.h"
00032 
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 233782 $")
00034 
00035 #include <unistd.h>
00036 #include <netinet/in.h>
00037 #include <arpa/inet.h>
00038 #include <stdlib.h>
00039 #include <sys/time.h>
00040 #include <stdio.h>
00041 #include <errno.h>
00042 #include <string.h>
00043 
00044 #include "asterisk/lock.h"
00045 #include "asterisk/options.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/file.h"
00048 #include "asterisk/logger.h"
00049 #include "asterisk/sched.h"
00050 #include "asterisk/module.h"
00051 #include "asterisk/endian.h"
00052 
00053 #define  RATE_40     0
00054 #define  RATE_32     1
00055 #define  RATE_24     2
00056 #define  RATE_16     3
00057 
00058 /* We can only read/write chunks of FRAME_TIME ms G.726 data */
00059 #define  FRAME_TIME  10 /* 10 ms size */
00060 
00061 #define  BUF_SIZE (5*FRAME_TIME) /* max frame size in bytes ? */
00062 /* Frame sizes in bytes */
00063 static int frame_size[4] = { 
00064       FRAME_TIME * 5,
00065       FRAME_TIME * 4,
00066       FRAME_TIME * 3,
00067       FRAME_TIME * 2
00068 };
00069 
00070 struct g726_desc  {
00071    int rate;   /* RATE_* defines */
00072 };
00073 
00074 /*
00075  * Rate dependant format functions (open, rewrite)
00076  */
00077 static int g726_open(struct ast_filestream *tmp, int rate)
00078 {
00079    struct g726_desc *s = (struct g726_desc *)tmp->_private;
00080    s->rate = rate;
00081    if (option_debug)
00082       ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
00083             40 - s->rate * 8);
00084    return 0;
00085 }
00086 
00087 static int g726_40_open(struct ast_filestream *s)
00088 {
00089    return g726_open(s, RATE_40);
00090 }
00091 
00092 static int g726_32_open(struct ast_filestream *s)
00093 {
00094    return g726_open(s, RATE_32);
00095 }
00096 
00097 static int g726_24_open(struct ast_filestream *s)
00098 {
00099    return g726_open(s, RATE_24);
00100 }
00101 
00102 static int g726_16_open(struct ast_filestream *s)
00103 {
00104    return g726_open(s, RATE_16);
00105 }
00106 
00107 static int g726_40_rewrite(struct ast_filestream *s, const char *comment)
00108 {
00109    return g726_open(s, RATE_40);
00110 }
00111 
00112 static int g726_32_rewrite(struct ast_filestream *s, const char *comment)
00113 {
00114    return g726_open(s, RATE_32);
00115 }
00116 
00117 static int g726_24_rewrite(struct ast_filestream *s, const char *comment)
00118 {
00119    return g726_open(s, RATE_24);
00120 }
00121 
00122 static int g726_16_rewrite(struct ast_filestream *s, const char *comment)
00123 {
00124    return g726_open(s, RATE_16);
00125 }
00126 
00127 /*
00128  * Rate independent format functions (read, write)
00129  */
00130 
00131 static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext)
00132 {
00133    int res;
00134    struct g726_desc *fs = (struct g726_desc *)s->_private;
00135 
00136    /* Send a frame from the file to the appropriate channel */
00137    s->fr.frametype = AST_FRAME_VOICE;
00138    s->fr.subclass = AST_FORMAT_G726;
00139    s->fr.mallocd = 0;
00140    AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, frame_size[fs->rate]);
00141    s->fr.samples = 8 * FRAME_TIME;
00142    if ((res = fread(s->fr.data, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
00143       if (res)
00144          ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
00145       return NULL;
00146    }
00147    *whennext = s->fr.samples;
00148    return &s->fr;
00149 }
00150 
00151 static int g726_write(struct ast_filestream *s, struct ast_frame *f)
00152 {
00153    int res;
00154    struct g726_desc *fs = (struct g726_desc *)s->_private;
00155 
00156    if (f->frametype != AST_FRAME_VOICE) {
00157       ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00158       return -1;
00159    }
00160    if (f->subclass != AST_FORMAT_G726) {
00161       ast_log(LOG_WARNING, "Asked to write non-G726 frame (%d)!\n", 
00162                   f->subclass);
00163       return -1;
00164    }
00165    if (f->datalen % frame_size[fs->rate]) {
00166       ast_log(LOG_WARNING, "Invalid data length %d, should be multiple of %d\n", 
00167                   f->datalen, frame_size[fs->rate]);
00168       return -1;
00169    }
00170    if ((res = fwrite(f->data, 1, f->datalen, s->f)) != f->datalen) {
00171       ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", 
00172             res, frame_size[fs->rate], strerror(errno));
00173          return -1;
00174    }
00175    return 0;
00176 }
00177 
00178 static int g726_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
00179 {
00180    return -1;
00181 }
00182 
00183 static int g726_trunc(struct ast_filestream *fs)
00184 {
00185    return -1;
00186 }
00187 
00188 static off_t g726_tell(struct ast_filestream *fs)
00189 {
00190    return -1;
00191 }
00192 
00193 static const struct ast_format f[] = {
00194    {
00195       .name = "g726-40",
00196       .exts = "g726-40",
00197       .format = AST_FORMAT_G726,
00198       .open = g726_40_open,
00199       .rewrite = g726_40_rewrite,
00200       .write = g726_write,
00201       .seek = g726_seek,
00202       .trunc = g726_trunc,
00203       .tell = g726_tell,
00204       .read = g726_read,
00205       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00206       .desc_size = sizeof(struct g726_desc),
00207    },
00208    {
00209       .name = "g726-32",
00210       .exts = "g726-32",
00211       .format = AST_FORMAT_G726,
00212       .open = g726_32_open,
00213       .rewrite = g726_32_rewrite,
00214       .write = g726_write,
00215       .seek = g726_seek,
00216       .trunc = g726_trunc,
00217       .tell = g726_tell,
00218       .read = g726_read,
00219       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00220       .desc_size = sizeof(struct g726_desc),
00221    },
00222    {
00223       .name = "g726-24",
00224       .exts = "g726-24",
00225       .format = AST_FORMAT_G726,
00226       .open = g726_24_open,
00227       .rewrite = g726_24_rewrite,
00228       .write = g726_write,
00229       .seek = g726_seek,
00230       .trunc = g726_trunc,
00231       .tell = g726_tell,
00232       .read = g726_read,
00233       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00234       .desc_size = sizeof(struct g726_desc),
00235    },
00236    {
00237       .name = "g726-16",
00238       .exts = "g726-16",
00239       .format = AST_FORMAT_G726,
00240       .open = g726_16_open,
00241       .rewrite = g726_16_rewrite,
00242       .write = g726_write,
00243       .seek = g726_seek,
00244       .trunc = g726_trunc,
00245       .tell = g726_tell,
00246       .read = g726_read,
00247       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
00248       .desc_size = sizeof(struct g726_desc),
00249    },
00250    {  .format = 0 }  /* terminator */
00251 };
00252 
00253 static int load_module(void)
00254 {
00255    int i;
00256 
00257    for (i = 0; f[i].format ; i++) {
00258       if (ast_format_register(&f[i])) {   /* errors are fatal */
00259          ast_log(LOG_WARNING, "Failed to register format %s.\n", f[i].name);
00260          return -1;
00261       }
00262    }
00263    return 0;
00264 }
00265 
00266 static int unload_module(void)
00267 {
00268    int i;
00269 
00270    for (i = 0; f[i].format ; i++) {
00271       if (ast_format_unregister(f[i].name))
00272          ast_log(LOG_WARNING, "Failed to unregister format %s.\n", f[i].name);
00273    }
00274    return(0);
00275 }  
00276 
00277 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_FIRST, "Raw G.726 (16/24/32/40kbps) data",
00278    .load = load_module,
00279    .unload = unload_module,
00280 );

Generated on Sat Aug 6 00:39:28 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7