Asterisk.org: Developer Documentation (28 Oct 2009)

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