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