Wed Oct 28 15:47:53 2009

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 <unistd.h>
00032 #include <netinet/in.h>
00033 #include <arpa/inet.h>
00034 #include <stdlib.h>
00035 #include <sys/time.h>
00036 #include <stdio.h>
00037 #include <errno.h>
00038 #include <string.h>
00039 
00040 #include "asterisk.h"
00041 
00042 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
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 /* Frame sizes in bytes */
00062 static int frame_size[4] = { 
00063       FRAME_TIME * 5,
00064       FRAME_TIME * 4,
00065       FRAME_TIME * 3,
00066       FRAME_TIME * 2
00067 };
00068 
00069 struct ast_filestream {
00070    /* Do not place anything before "reserved" */
00071    void *reserved[AST_RESERVED_POINTERS];
00072    /* This is what a filestream means to us */
00073    FILE *f;                      /* Open file descriptor */
00074    int rate;                     /* RATE_* defines */
00075    struct ast_frame fr;          /* Frame information */
00076    char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
00077    char empty;                   /* Empty character */
00078    unsigned char g726[FRAME_TIME * 5]; /* G.726 encoded voice */
00079 };
00080 
00081 AST_MUTEX_DEFINE_STATIC(g726_lock);
00082 static int glistcnt = 0;
00083 
00084 static char *desc = "Raw G.726 (16/24/32/40kbps) data";
00085 static char *name40 = "g726-40";
00086 static char *name32 = "g726-32";
00087 static char *name24 = "g726-24";
00088 static char *name16 = "g726-16";
00089 static char *exts40 = "g726-40";
00090 static char *exts32 = "g726-32";
00091 static char *exts24 = "g726-24";
00092 static char *exts16 = "g726-16";
00093 
00094 /*
00095  * Rate dependant format functions (open, rewrite)
00096  */
00097 static struct ast_filestream *g726_40_open(FILE *f)
00098 {
00099    /* We don't have any header to read or anything really, but
00100       if we did, it would go here.  We also might want to check
00101       and be sure it's a valid file.  */
00102    struct ast_filestream *tmp;
00103    if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00104       memset(tmp, 0, sizeof(struct ast_filestream));
00105       if (ast_mutex_lock(&g726_lock)) {
00106          ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
00107          free(tmp);
00108          return NULL;
00109       }
00110       tmp->f = f;
00111       tmp->rate = RATE_40;
00112       tmp->fr.data = tmp->g726;
00113       tmp->fr.frametype = AST_FRAME_VOICE;
00114       tmp->fr.subclass = AST_FORMAT_G726;
00115       /* datalen will vary for each frame */
00116       tmp->fr.src = name40;
00117       tmp->fr.mallocd = 0;
00118       glistcnt++;
00119       if (option_debug)
00120          ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
00121                            40 - tmp->rate * 8);
00122       ast_mutex_unlock(&g726_lock);
00123       ast_update_use_count();
00124    }
00125    return tmp;
00126 }
00127 
00128 static struct ast_filestream *g726_32_open(FILE *f)
00129 {
00130    /* We don't have any header to read or anything really, but
00131       if we did, it would go here.  We also might want to check
00132       and be sure it's a valid file.  */
00133    struct ast_filestream *tmp;
00134    if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00135       memset(tmp, 0, sizeof(struct ast_filestream));
00136       if (ast_mutex_lock(&g726_lock)) {
00137          ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
00138          free(tmp);
00139          return NULL;
00140       }
00141       tmp->f = f;
00142       tmp->rate = RATE_32;
00143       tmp->fr.data = tmp->g726;
00144       tmp->fr.frametype = AST_FRAME_VOICE;
00145       tmp->fr.subclass = AST_FORMAT_G726;
00146       /* datalen will vary for each frame */
00147       tmp->fr.src = name32;
00148       tmp->fr.mallocd = 0;
00149       glistcnt++;
00150       if (option_debug)
00151          ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
00152                            40 - tmp->rate * 8);
00153       ast_mutex_unlock(&g726_lock);
00154       ast_update_use_count();
00155    }
00156    return tmp;
00157 }
00158 
00159 static struct ast_filestream *g726_24_open(FILE *f)
00160 {
00161    /* We don't have any header to read or anything really, but
00162       if we did, it would go here.  We also might want to check
00163       and be sure it's a valid file.  */
00164    struct ast_filestream *tmp;
00165    if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00166       memset(tmp, 0, sizeof(struct ast_filestream));
00167       if (ast_mutex_lock(&g726_lock)) {
00168          ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
00169          free(tmp);
00170          return NULL;
00171       }
00172       tmp->f = f;
00173       tmp->rate = RATE_24;
00174       tmp->fr.data = tmp->g726;
00175       tmp->fr.frametype = AST_FRAME_VOICE;
00176       tmp->fr.subclass = AST_FORMAT_G726;
00177       /* datalen will vary for each frame */
00178       tmp->fr.src = name24;
00179       tmp->fr.mallocd = 0;
00180       glistcnt++;
00181       if (option_debug)
00182          ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
00183                            40 - tmp->rate * 8);
00184       ast_mutex_unlock(&g726_lock);
00185       ast_update_use_count();
00186    }
00187    return tmp;
00188 }
00189 
00190 static struct ast_filestream *g726_16_open(FILE *f)
00191 {
00192    /* We don't have any header to read or anything really, but
00193       if we did, it would go here.  We also might want to check
00194       and be sure it's a valid file.  */
00195    struct ast_filestream *tmp;
00196    if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00197       memset(tmp, 0, sizeof(struct ast_filestream));
00198       if (ast_mutex_lock(&g726_lock)) {
00199          ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
00200          free(tmp);
00201          return NULL;
00202       }
00203       tmp->f = f;
00204       tmp->rate = RATE_16;
00205       tmp->fr.data = tmp->g726;
00206       tmp->fr.frametype = AST_FRAME_VOICE;
00207       tmp->fr.subclass = AST_FORMAT_G726;
00208       /* datalen will vary for each frame */
00209       tmp->fr.src = name16;
00210       tmp->fr.mallocd = 0;
00211       glistcnt++;
00212       if (option_debug)
00213          ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
00214                            40 - tmp->rate * 8);
00215       ast_mutex_unlock(&g726_lock);
00216       ast_update_use_count();
00217    }
00218    return tmp;
00219 }
00220 
00221 static struct ast_filestream *g726_40_rewrite(FILE *f, const char *comment)
00222 {
00223    /* We don't have any header to read or anything really, but
00224       if we did, it would go here.  We also might want to check
00225       and be sure it's a valid file.  */
00226    struct ast_filestream *tmp;
00227    if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00228       memset(tmp, 0, sizeof(struct ast_filestream));
00229       if (ast_mutex_lock(&g726_lock)) {
00230          ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
00231          free(tmp);
00232          return NULL;
00233       }
00234       tmp->f = f;
00235       tmp->rate = RATE_40;
00236       glistcnt++;
00237       if (option_debug)
00238          ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
00239                            40 - tmp->rate * 8);
00240       ast_mutex_unlock(&g726_lock);
00241       ast_update_use_count();
00242    } else
00243       ast_log(LOG_WARNING, "Out of memory\n");
00244    return tmp;
00245 }
00246 
00247 static struct ast_filestream *g726_32_rewrite(FILE *f, const char *comment)
00248 {
00249    /* We don't have any header to read or anything really, but
00250       if we did, it would go here.  We also might want to check
00251       and be sure it's a valid file.  */
00252    struct ast_filestream *tmp;
00253    if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00254       memset(tmp, 0, sizeof(struct ast_filestream));
00255       if (ast_mutex_lock(&g726_lock)) {
00256          ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
00257          free(tmp);
00258          return NULL;
00259       }
00260       tmp->f = f;
00261       tmp->rate = RATE_32;
00262       glistcnt++;
00263       if (option_debug)
00264          ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
00265                            40 - tmp->rate * 8);
00266       ast_mutex_unlock(&g726_lock);
00267       ast_update_use_count();
00268    } else
00269       ast_log(LOG_WARNING, "Out of memory\n");
00270    return tmp;
00271 }
00272 
00273 static struct ast_filestream *g726_24_rewrite(FILE *f, const char *comment)
00274 {
00275    /* We don't have any header to read or anything really, but
00276       if we did, it would go here.  We also might want to check
00277       and be sure it's a valid file.  */
00278    struct ast_filestream *tmp;
00279    if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00280       memset(tmp, 0, sizeof(struct ast_filestream));
00281       if (ast_mutex_lock(&g726_lock)) {
00282          ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
00283          free(tmp);
00284          return NULL;
00285       }
00286       tmp->f = f;
00287       tmp->rate = RATE_24;
00288       glistcnt++;
00289       if (option_debug)
00290          ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
00291                            40 - tmp->rate * 8);
00292       ast_mutex_unlock(&g726_lock);
00293       ast_update_use_count();
00294    } else
00295       ast_log(LOG_WARNING, "Out of memory\n");
00296    return tmp;
00297 }
00298 
00299 static struct ast_filestream *g726_16_rewrite(FILE *f, const char *comment)
00300 {
00301    /* We don't have any header to read or anything really, but
00302       if we did, it would go here.  We also might want to check
00303       and be sure it's a valid file.  */
00304    struct ast_filestream *tmp;
00305    if ((tmp = malloc(sizeof(struct ast_filestream)))) {
00306       memset(tmp, 0, sizeof(struct ast_filestream));
00307       if (ast_mutex_lock(&g726_lock)) {
00308          ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
00309          free(tmp);
00310          return NULL;
00311       }
00312       tmp->f = f;
00313       tmp->rate = RATE_16;
00314       glistcnt++;
00315       if (option_debug)
00316          ast_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 
00317                            40 - tmp->rate * 8);
00318       ast_mutex_unlock(&g726_lock);
00319       ast_update_use_count();
00320    } else
00321       ast_log(LOG_WARNING, "Out of memory\n");
00322    return tmp;
00323 }
00324 
00325 /*
00326  * Rate independent format functions (close, read, write)
00327  */
00328 static void g726_close(struct ast_filestream *s)
00329 {
00330    if (ast_mutex_lock(&g726_lock)) {
00331       ast_log(LOG_WARNING, "Unable to lock g726 list.\n");
00332       return;
00333    }
00334    glistcnt--;
00335    if (option_debug)
00336       ast_log(LOG_DEBUG, "Closed filestream G.726-%dk.\n", 40 - s->rate * 8);
00337    ast_mutex_unlock(&g726_lock);
00338    ast_update_use_count();
00339    fclose(s->f);
00340    free(s);
00341    s = NULL;
00342 }
00343 
00344 static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext)
00345 {
00346    int res;
00347    /* Send a frame from the file to the appropriate channel */
00348    s->fr.frametype = AST_FRAME_VOICE;
00349    s->fr.subclass = AST_FORMAT_G726;
00350    s->fr.offset = AST_FRIENDLY_OFFSET;
00351    s->fr.samples = 8 * FRAME_TIME;
00352    s->fr.datalen = frame_size[s->rate];
00353    s->fr.mallocd = 0;
00354    s->fr.data = s->g726;
00355    if ((res = fread(s->g726, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
00356       if (res)
00357          ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
00358       return NULL;
00359    }
00360    *whennext = s->fr.samples;
00361    return &s->fr;
00362 }
00363 
00364 static int g726_write(struct ast_filestream *fs, struct ast_frame *f)
00365 {
00366    int res;
00367    if (f->frametype != AST_FRAME_VOICE) {
00368       ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
00369       return -1;
00370    }
00371    if (f->subclass != AST_FORMAT_G726) {
00372       ast_log(LOG_WARNING, "Asked to write non-G726 frame (%d)!\n", 
00373                   f->subclass);
00374       return -1;
00375    }
00376    if (f->datalen % frame_size[fs->rate]) {
00377       ast_log(LOG_WARNING, "Invalid data length %d, should be multiple of %d\n", 
00378                   f->datalen, frame_size[fs->rate]);
00379       return -1;
00380    }
00381    if ((res = fwrite(f->data, 1, f->datalen, fs->f)) != f->datalen) {
00382          ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", 
00383                      res, frame_size[fs->rate], strerror(errno));
00384          return -1;
00385    }
00386    return 0;
00387 }
00388 
00389 static char *g726_getcomment(struct ast_filestream *s)
00390 {
00391    return NULL;
00392 }
00393 
00394 static int g726_seek(struct ast_filestream *fs, long sample_offset, int whence)
00395 {
00396    return -1;
00397 }
00398 
00399 static int g726_trunc(struct ast_filestream *fs)
00400 {
00401    return -1;
00402 }
00403 
00404 static long g726_tell(struct ast_filestream *fs)
00405 {
00406    return -1;
00407 }
00408 
00409 /*
00410  * Module interface (load_module, unload_module, usecount, description, key)
00411  */
00412 int load_module()
00413 {
00414    int res;
00415 
00416    res = ast_format_register(name40, exts40, AST_FORMAT_G726,
00417                         g726_40_open,
00418                         g726_40_rewrite,
00419                         g726_write,
00420                         g726_seek,
00421                         g726_trunc,
00422                         g726_tell,
00423                         g726_read,
00424                         g726_close,
00425                         g726_getcomment);
00426    if (res) {
00427       ast_log(LOG_WARNING, "Failed to register format %s.\n", name40);
00428       return(-1);
00429    }
00430    res = ast_format_register(name32, exts32, AST_FORMAT_G726,
00431                         g726_32_open,
00432                         g726_32_rewrite,
00433                         g726_write,
00434                         g726_seek,
00435                         g726_trunc,
00436                         g726_tell,
00437                         g726_read,
00438                         g726_close,
00439                         g726_getcomment);
00440    if (res) {
00441       ast_log(LOG_WARNING, "Failed to register format %s.\n", name32);
00442       return(-1);
00443    }
00444    res = ast_format_register(name24, exts24, AST_FORMAT_G726,
00445                         g726_24_open,
00446                         g726_24_rewrite,
00447                         g726_write,
00448                         g726_seek,
00449                         g726_trunc,
00450                         g726_tell,
00451                         g726_read,
00452                         g726_close,
00453                         g726_getcomment);
00454    if (res) {
00455       ast_log(LOG_WARNING, "Failed to register format %s.\n", name24);
00456       return(-1);
00457    }
00458    res = ast_format_register(name16, exts16, AST_FORMAT_G726,
00459                         g726_16_open,
00460                         g726_16_rewrite,
00461                         g726_write,
00462                         g726_seek,
00463                         g726_trunc,
00464                         g726_tell,
00465                         g726_read,
00466                         g726_close,
00467                         g726_getcomment);
00468    if (res) {
00469       ast_log(LOG_WARNING, "Failed to register format %s.\n", name16);
00470       return(-1);
00471    }
00472    return(0);
00473 }
00474 
00475 int unload_module()
00476 {
00477    int res;
00478 
00479    res = ast_format_unregister(name16);
00480    if (res) {
00481       ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name16);
00482       return(-1);
00483    }
00484    res = ast_format_unregister(name24);
00485    if (res) {
00486       ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name24);
00487       return(-1);
00488    }
00489    res = ast_format_unregister(name32);
00490    if (res) {
00491       ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name32);
00492       return(-1);
00493    }
00494    res = ast_format_unregister(name40);
00495    if (res) {
00496       ast_log(LOG_WARNING, "Failed to unregister format %s.\n", name40);
00497       return(-1);
00498    }
00499    return(0);
00500 }  
00501 
00502 int usecount()
00503 {
00504    return glistcnt;
00505 }
00506 
00507 char *description()
00508 {
00509    return desc;
00510 }
00511 
00512 char *key()
00513 {
00514    return ASTERISK_GPL_KEY;
00515 }
00516 

Generated on Wed Oct 28 15:47:54 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6