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
00029
00030
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 98943 $")
00037
00038 #include <fcntl.h>
00039 #include <stdlib.h>
00040 #include <unistd.h>
00041 #include <netinet/in.h>
00042 #include <string.h>
00043 #include <stdio.h>
00044 #include <sys/ioctl.h>
00045 #include <errno.h>
00046 #include <sys/mman.h>
00047 #include <zaptel/zaptel.h>
00048
00049 #include "asterisk/lock.h"
00050 #include "asterisk/translate.h"
00051 #include "asterisk/config.h"
00052 #include "asterisk/options.h"
00053 #include "asterisk/module.h"
00054 #include "asterisk/cli.h"
00055 #include "asterisk/logger.h"
00056 #include "asterisk/channel.h"
00057 #include "asterisk/utils.h"
00058 #include "asterisk/linkedlists.h"
00059
00060 #define BUFFER_SAMPLES 8000
00061
00062 static unsigned int global_useplc = 0;
00063
00064 static struct channel_usage {
00065 int total;
00066 int encoders;
00067 int decoders;
00068 } channels;
00069
00070 static char show_transcoder_usage[] =
00071 "Usage: show transcoder\n"
00072 " Displays channel utilization of Zaptel transcoder(s).\n";
00073
00074 static char transcoder_show_usage[] =
00075 "Usage: transcoder show\n"
00076 " Displays channel utilization of Zaptel transcoder(s).\n";
00077
00078 static int transcoder_show(int fd, int argc, char **argv);
00079
00080 static struct ast_cli_entry cli_deprecated[] = {
00081 { { "show", "transcoder", NULL },
00082 transcoder_show,
00083 "Display Zaptel transcoder utilization.",
00084 show_transcoder_usage}
00085 };
00086
00087 static struct ast_cli_entry cli[] = {
00088 { { "transcoder", "show", NULL },
00089 transcoder_show,
00090 "Display Zaptel transcoder utilization.",
00091 transcoder_show_usage, NULL,
00092 &cli_deprecated[0]}
00093 };
00094
00095 struct format_map {
00096 unsigned int map[32][32];
00097 };
00098
00099 static struct format_map global_format_map = { { { 0 } } };
00100
00101 struct translator {
00102 struct ast_translator t;
00103 AST_LIST_ENTRY(translator) entry;
00104 };
00105
00106 static AST_LIST_HEAD_STATIC(translators, translator);
00107
00108 struct pvt {
00109 int fd;
00110 int fake;
00111 unsigned int g729b_warning:1;
00112 #ifdef DEBUG_TRANSCODE
00113 int totalms;
00114 int lasttotalms;
00115 #endif
00116 struct zt_transcode_header *hdr;
00117 };
00118
00119 static int transcoder_show(int fd, int argc, char **argv)
00120 {
00121 struct channel_usage copy;
00122
00123 copy = channels;
00124
00125 if (copy.total == 0)
00126 ast_cli(fd, "No Zaptel transcoders found.\n");
00127 else
00128 ast_cli(fd, "%d/%d encoders/decoders of %d channels are in use.\n", copy.encoders, copy.decoders, copy.total);
00129
00130 return RESULT_SUCCESS;
00131 }
00132
00133 static int zap_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00134 {
00135 struct pvt *ztp = pvt->pvt;
00136 struct zt_transcode_header *hdr = ztp->hdr;
00137
00138 if (!f->subclass) {
00139
00140 ztp->fake = 2;
00141 pvt->samples = f->samples;
00142 return 0;
00143 }
00144
00145 if (!hdr->srclen)
00146
00147 hdr->srcoffset = 0;
00148
00149
00150
00151
00152
00153 if ((f->subclass == AST_FORMAT_G729A) && ((f->datalen % 10) != 0)) {
00154 if (!ztp->g729b_warning) {
00155 ast_log(LOG_WARNING, "G.729B CNG frame received but is not supported; dropping.\n");
00156 ztp->g729b_warning = 1;
00157 }
00158 f->datalen -= f->datalen % 10;
00159 f->samples = f->datalen * 8;
00160 }
00161
00162 if (hdr->srclen + f->datalen > sizeof(hdr->srcdata)) {
00163 ast_log(LOG_WARNING, "Out of space for codec translation!\n");
00164 return -1;
00165 }
00166
00167 if (hdr->srclen + f->datalen + hdr->srcoffset > sizeof(hdr->srcdata)) {
00168
00169 memmove(hdr->srcdata, hdr->srcdata + hdr->srcoffset, hdr->srclen);
00170 hdr->srcoffset = 0;
00171 }
00172
00173 memcpy(hdr->srcdata + hdr->srcoffset + hdr->srclen, f->data, f->datalen);
00174 hdr->srclen += f->datalen;
00175 pvt->samples += f->samples;
00176
00177 return -1;
00178 }
00179
00180 static struct ast_frame *zap_frameout(struct ast_trans_pvt *pvt)
00181 {
00182 struct pvt *ztp = pvt->pvt;
00183 struct zt_transcode_header *hdr = ztp->hdr;
00184 unsigned int x;
00185
00186 if (ztp->fake == 2) {
00187 ztp->fake = 1;
00188 pvt->f.frametype = AST_FRAME_VOICE;
00189 pvt->f.subclass = 0;
00190 pvt->f.samples = 160;
00191 pvt->f.data = NULL;
00192 pvt->f.offset = 0;
00193 pvt->f.datalen = 0;
00194 pvt->f.mallocd = 0;
00195 ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
00196 pvt->samples = 0;
00197 } else if (ztp->fake == 1) {
00198 return NULL;
00199 } else {
00200 if (hdr->dstlen) {
00201 #ifdef DEBUG_TRANSCODE
00202 ztp->totalms += hdr->dstsamples;
00203 if ((ztp->totalms - ztp->lasttotalms) > 8000) {
00204 printf("Whee %p, %d (%d to %d)\n", ztp, hdr->dstlen, ztp->lasttotalms, ztp->totalms);
00205 ztp->lasttotalms = ztp->totalms;
00206 }
00207 #endif
00208 pvt->f.frametype = AST_FRAME_VOICE;
00209 pvt->f.subclass = hdr->dstfmt;
00210 pvt->f.samples = hdr->dstsamples;
00211 pvt->f.data = hdr->dstdata + hdr->dstoffset;
00212 pvt->f.offset = hdr->dstoffset;
00213 pvt->f.datalen = hdr->dstlen;
00214 pvt->f.mallocd = 0;
00215 ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
00216 pvt->samples -= pvt->f.samples;
00217 hdr->dstlen = 0;
00218
00219 } else {
00220 if (hdr->srclen) {
00221 hdr->dstoffset = AST_FRIENDLY_OFFSET;
00222 x = ZT_TCOP_TRANSCODE;
00223 if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x))
00224 ast_log(LOG_WARNING, "Failed to transcode: %s\n", strerror(errno));
00225 }
00226 return NULL;
00227 }
00228 }
00229
00230 return &pvt->f;
00231 }
00232
00233 static void zap_destroy(struct ast_trans_pvt *pvt)
00234 {
00235 struct pvt *ztp = pvt->pvt;
00236 unsigned int x;
00237
00238 x = ZT_TCOP_RELEASE;
00239 if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x))
00240 ast_log(LOG_WARNING, "Failed to release transcoder channel: %s\n", strerror(errno));
00241
00242 switch (ztp->hdr->dstfmt) {
00243 case AST_FORMAT_G729A:
00244 case AST_FORMAT_G723_1:
00245 ast_atomic_fetchadd_int(&channels.encoders, -1);
00246 break;
00247 default:
00248 ast_atomic_fetchadd_int(&channels.decoders, -1);
00249 break;
00250 }
00251
00252 munmap(ztp->hdr, sizeof(*ztp->hdr));
00253 close(ztp->fd);
00254 }
00255
00256 static int zap_translate(struct ast_trans_pvt *pvt, int dest, int source)
00257 {
00258
00259 int fd;
00260 unsigned int x = ZT_TCOP_ALLOCATE;
00261 struct pvt *ztp = pvt->pvt;
00262 struct zt_transcode_header *hdr;
00263 int flags;
00264
00265 if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0)
00266 return -1;
00267 flags = fcntl(fd, F_GETFL);
00268 if (flags > - 1) {
00269 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
00270 ast_log(LOG_WARNING, "Could not set non-block mode!\n");
00271 }
00272
00273
00274 if ((hdr = mmap(NULL, sizeof(*hdr), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
00275 ast_log(LOG_ERROR, "Memory Map failed for transcoding (%s)\n", strerror(errno));
00276 close(fd);
00277
00278 return -1;
00279 }
00280
00281 if (hdr->magic != ZT_TRANSCODE_MAGIC) {
00282 ast_log(LOG_ERROR, "Transcoder header (%08x) wasn't magic. Abandoning\n", hdr->magic);
00283 munmap(hdr, sizeof(*hdr));
00284 close(fd);
00285
00286 return -1;
00287 }
00288
00289 hdr->srcfmt = (1 << source);
00290 hdr->dstfmt = (1 << dest);
00291 if (ioctl(fd, ZT_TRANSCODE_OP, &x)) {
00292 ast_log(LOG_ERROR, "Unable to attach transcoder: %s\n", strerror(errno));
00293 munmap(hdr, sizeof(*hdr));
00294 close(fd);
00295
00296 return -1;
00297 }
00298
00299 ztp = pvt->pvt;
00300 ztp->fd = fd;
00301 ztp->hdr = hdr;
00302
00303 switch (hdr->dstfmt) {
00304 case AST_FORMAT_G729A:
00305 case AST_FORMAT_G723_1:
00306 ast_atomic_fetchadd_int(&channels.encoders, +1);
00307 break;
00308 default:
00309 ast_atomic_fetchadd_int(&channels.decoders, +1);
00310 break;
00311 }
00312
00313 return 0;
00314 }
00315
00316 static int zap_new(struct ast_trans_pvt *pvt)
00317 {
00318 return zap_translate(pvt, pvt->t->dstfmt, pvt->t->srcfmt);
00319 }
00320
00321 static struct ast_frame *fakesrc_sample(void)
00322 {
00323
00324 static struct ast_frame f = {
00325 .frametype = AST_FRAME_VOICE,
00326 .samples = 160,
00327 .src = __PRETTY_FUNCTION__
00328 };
00329
00330 return &f;
00331 }
00332
00333 static int register_translator(int dst, int src)
00334 {
00335 struct translator *zt;
00336 int res;
00337
00338 if (!(zt = ast_calloc(1, sizeof(*zt))))
00339 return -1;
00340
00341 snprintf((char *) (zt->t.name), sizeof(zt->t.name), "zap%sto%s",
00342 ast_getformatname((1 << src)), ast_getformatname((1 << dst)));
00343 zt->t.srcfmt = (1 << src);
00344 zt->t.dstfmt = (1 << dst);
00345 zt->t.newpvt = zap_new;
00346 zt->t.framein = zap_framein;
00347 zt->t.frameout = zap_frameout;
00348 zt->t.destroy = zap_destroy;
00349 zt->t.sample = fakesrc_sample;
00350 zt->t.useplc = global_useplc;
00351 zt->t.buf_size = BUFFER_SAMPLES * 2;
00352 zt->t.desc_size = sizeof(struct pvt);
00353 if ((res = ast_register_translator(&zt->t))) {
00354 free(zt);
00355 return -1;
00356 }
00357
00358 AST_LIST_LOCK(&translators);
00359 AST_LIST_INSERT_HEAD(&translators, zt, entry);
00360 AST_LIST_UNLOCK(&translators);
00361
00362 global_format_map.map[dst][src] = 1;
00363
00364 return res;
00365 }
00366
00367 static void drop_translator(int dst, int src)
00368 {
00369 struct translator *cur;
00370
00371 AST_LIST_LOCK(&translators);
00372 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators, cur, entry) {
00373 if (cur->t.srcfmt != src)
00374 continue;
00375
00376 if (cur->t.dstfmt != dst)
00377 continue;
00378
00379 AST_LIST_REMOVE_CURRENT(&translators, entry);
00380 ast_unregister_translator(&cur->t);
00381 free(cur);
00382 global_format_map.map[dst][src] = 0;
00383 break;
00384 }
00385 AST_LIST_TRAVERSE_SAFE_END;
00386 AST_LIST_UNLOCK(&translators);
00387 }
00388
00389 static void unregister_translators(void)
00390 {
00391 struct translator *cur;
00392
00393 AST_LIST_LOCK(&translators);
00394 while ((cur = AST_LIST_REMOVE_HEAD(&translators, entry))) {
00395 ast_unregister_translator(&cur->t);
00396 free(cur);
00397 }
00398 AST_LIST_UNLOCK(&translators);
00399 }
00400
00401 static void parse_config(void)
00402 {
00403 struct ast_variable *var;
00404 struct ast_config *cfg = ast_config_load("codecs.conf");
00405
00406 if (!cfg)
00407 return;
00408
00409 for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
00410 if (!strcasecmp(var->name, "genericplc")) {
00411 global_useplc = ast_true(var->value);
00412 if (option_verbose > 2)
00413 ast_verbose(VERBOSE_PREFIX_3 "codec_zap: %susing generic PLC\n",
00414 global_useplc ? "" : "not ");
00415 }
00416 }
00417
00418 ast_config_destroy(cfg);
00419 }
00420
00421 static void build_translators(struct format_map *map, unsigned int dstfmts, unsigned int srcfmts)
00422 {
00423 unsigned int src, dst;
00424
00425 for (src = 0; src < 32; src++) {
00426 for (dst = 0; dst < 32; dst++) {
00427 if (!(srcfmts & (1 << src)))
00428 continue;
00429
00430 if (!(dstfmts & (1 << dst)))
00431 continue;
00432
00433 if (global_format_map.map[dst][src])
00434 continue;
00435
00436 if (!register_translator(dst, src))
00437 map->map[dst][src] = 1;
00438 }
00439 }
00440 }
00441
00442 static int find_transcoders(void)
00443 {
00444 struct zt_transcode_info info = { 0, };
00445 struct format_map map = { { { 0 } } };
00446 int fd, res;
00447 unsigned int x, y;
00448
00449 if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) {
00450 ast_verbose(VERBOSE_PREFIX_2 "No hardware transcoders found.\n");
00451 return 0;
00452 }
00453
00454 info.op = ZT_TCOP_GETINFO;
00455 for (info.tcnum = 0; !(res = ioctl(fd, ZT_TRANSCODE_OP, &info)); info.tcnum++) {
00456 if (option_verbose > 1)
00457 ast_verbose(VERBOSE_PREFIX_2 "Found transcoder '%s'.\n", info.name);
00458 build_translators(&map, info.dstfmts, info.srcfmts);
00459 ast_atomic_fetchadd_int(&channels.total, info.numchannels / 2);
00460 }
00461
00462 close(fd);
00463
00464 if (!info.tcnum && (option_verbose > 1))
00465 ast_verbose(VERBOSE_PREFIX_2 "No hardware transcoders found.\n");
00466
00467 for (x = 0; x < 32; x++) {
00468 for (y = 0; y < 32; y++) {
00469 if (!map.map[x][y] && global_format_map.map[x][y])
00470 drop_translator(x, y);
00471 }
00472 }
00473
00474 return 0;
00475 }
00476
00477 static int reload(void)
00478 {
00479 struct translator *cur;
00480
00481 parse_config();
00482
00483 AST_LIST_LOCK(&translators);
00484 AST_LIST_TRAVERSE(&translators, cur, entry)
00485 cur->t.useplc = global_useplc;
00486 AST_LIST_UNLOCK(&translators);
00487
00488 return 0;
00489 }
00490
00491 static int unload_module(void)
00492 {
00493 ast_cli_unregister_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00494 unregister_translators();
00495
00496 return 0;
00497 }
00498
00499 static int load_module(void)
00500 {
00501 parse_config();
00502 find_transcoders();
00503 ast_cli_register_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00504
00505 return 0;
00506 }
00507
00508 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Generic Zaptel Transcoder Codec Translator",
00509 .load = load_module,
00510 .unload = unload_module,
00511 .reload = reload,
00512 );