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: 224931 $")
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 <sys/poll.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 #include "asterisk/dahdi_compat.h"
00060 #include "asterisk/frame.h"
00061 #include "asterisk/ulaw.h"
00062
00063 #define BUFFER_SIZE 8000
00064
00065 #define G723_SAMPLES 240
00066 #define G729_SAMPLES 160
00067
00068 static unsigned int global_useplc = 0;
00069
00070 static struct channel_usage {
00071 int total;
00072 int encoders;
00073 int decoders;
00074 } channels;
00075
00076 static char show_transcoder_usage[] =
00077 "Usage: show transcoder\n"
00078 " Displays channel utilization of DAHDI transcoder(s).\n";
00079
00080 static char transcoder_show_usage[] =
00081 "Usage: transcoder show\n"
00082 " Displays channel utilization of DAHDI transcoder(s).\n";
00083
00084 static int transcoder_show(int fd, int argc, char **argv);
00085
00086 static struct ast_cli_entry cli_deprecated[] = {
00087 { { "show", "transcoder", NULL },
00088 transcoder_show,
00089 "Display DAHDI transcoder utilization.",
00090 show_transcoder_usage}
00091 };
00092
00093 static struct ast_cli_entry cli[] = {
00094 { { "transcoder", "show", NULL },
00095 transcoder_show,
00096 "Display DAHDI transcoder utilization.",
00097 transcoder_show_usage, NULL,
00098 &cli_deprecated[0]}
00099 };
00100
00101 struct format_map {
00102 unsigned int map[32][32];
00103 };
00104
00105 static struct format_map global_format_map = { { { 0 } } };
00106
00107 struct translator {
00108 struct ast_translator t;
00109 AST_LIST_ENTRY(translator) entry;
00110 };
00111
00112 static AST_LIST_HEAD_STATIC(translators, translator);
00113
00114 struct codec_dahdi_pvt {
00115 int fd;
00116 struct dahdi_transcoder_formats fmts;
00117 unsigned int softslin:1;
00118 unsigned int fake:2;
00119 uint16_t required_samples;
00120 uint16_t samples_in_buffer;
00121 uint8_t ulaw_buffer[1024];
00122 };
00123
00124
00125 static int ulawtolin(struct ast_trans_pvt *pvt)
00126 {
00127 struct codec_dahdi_pvt *ztp = pvt->pvt;
00128 int i = ztp->required_samples;
00129 uint8_t *src = &ztp->ulaw_buffer[0];
00130 int16_t *dst = (int16_t *)pvt->outbuf + pvt->datalen;
00131
00132
00133 while (i--) {
00134 *dst++ = AST_MULAW(*src++);
00135 }
00136
00137 return 0;
00138 }
00139
00140
00141 static int lintoulaw(struct ast_trans_pvt *pvt, struct ast_frame *f)
00142 {
00143 struct codec_dahdi_pvt *ztp = pvt->pvt;
00144 int i = f->samples;
00145 uint8_t *dst = &ztp->ulaw_buffer[ztp->samples_in_buffer];
00146 int16_t *src = (int16_t*)f->data;
00147
00148 if (ztp->samples_in_buffer + i > sizeof(ztp->ulaw_buffer)) {
00149 ast_log(LOG_ERROR, "Out of buffer space!\n");
00150 return -i;
00151 }
00152
00153 while (i--) {
00154 *dst++ = AST_LIN2MU(*src++);
00155 }
00156
00157 ztp->samples_in_buffer += f->samples;
00158 return 0;
00159 }
00160
00161 static int transcoder_show(int fd, int argc, char **argv)
00162 {
00163 struct channel_usage copy;
00164
00165 copy = channels;
00166
00167 if (copy.total == 0)
00168 ast_cli(fd, "No DAHDI transcoders found.\n");
00169 else
00170 ast_cli(fd, "%d/%d encoders/decoders of %d channels are in use.\n", copy.encoders, copy.decoders, copy.total);
00171
00172 return RESULT_SUCCESS;
00173 }
00174
00175 static void dahdi_write_frame(struct codec_dahdi_pvt *ztp, const uint8_t *buffer, const ssize_t count)
00176 {
00177 int res;
00178 struct pollfd p = {0};
00179 if (!count) return;
00180 res = write(ztp->fd, buffer, count);
00181 if (option_verbose > 10) {
00182 if (-1 == res) {
00183 ast_log(LOG_ERROR, "Failed to write to transcoder: %s\n", strerror(errno));
00184 }
00185 if (count != res) {
00186 ast_log(LOG_ERROR, "Requested write of %zd bytes, but only wrote %d bytes.\n", count, res);
00187 }
00188 }
00189 p.fd = ztp->fd;
00190 p.events = POLLOUT;
00191 res = poll(&p, 1, 50);
00192 }
00193
00194 static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00195 {
00196 struct codec_dahdi_pvt *ztp = pvt->pvt;
00197
00198 if (!f->subclass) {
00199
00200 ztp->fake = 2;
00201 pvt->samples = f->samples;
00202 return 0;
00203 }
00204
00205
00206
00207 if (ztp->softslin) {
00208 if (lintoulaw(pvt, f)) {
00209 return -1;
00210 }
00211 } else {
00212
00213
00214
00215
00216 if (ztp->samples_in_buffer + f->samples > sizeof(ztp->ulaw_buffer)) {
00217 ast_log(LOG_ERROR, "Out of buffer space.\n");
00218 return -1;
00219 }
00220 memcpy(&ztp->ulaw_buffer[ztp->samples_in_buffer], f->data, f->samples);
00221 ztp->samples_in_buffer += f->samples;
00222 }
00223
00224 while (ztp->samples_in_buffer > ztp->required_samples) {
00225 dahdi_write_frame(ztp, ztp->ulaw_buffer, ztp->required_samples);
00226 ztp->samples_in_buffer -= ztp->required_samples;
00227 if (ztp->samples_in_buffer) {
00228
00229 memmove(ztp->ulaw_buffer, &ztp->ulaw_buffer[ztp->required_samples],
00230 ztp->samples_in_buffer);
00231 }
00232 }
00233 pvt->samples += f->samples;
00234 pvt->datalen = 0;
00235 return -1;
00236 }
00237
00238 static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt)
00239 {
00240 struct codec_dahdi_pvt *ztp = pvt->pvt;
00241 int res;
00242
00243 if (2 == ztp->fake) {
00244 ztp->fake = 1;
00245 pvt->f.frametype = AST_FRAME_VOICE;
00246 pvt->f.subclass = 0;
00247 pvt->f.samples = ztp->required_samples;
00248 pvt->f.data = NULL;
00249 pvt->f.offset = 0;
00250 pvt->f.datalen = 0;
00251 pvt->f.mallocd = 0;
00252 pvt->samples = 0;
00253
00254 return ast_frisolate(&pvt->f);
00255
00256 } else if (1 == ztp->fake) {
00257 ztp->fake = 0;
00258 return NULL;
00259 }
00260
00261 res = read(ztp->fd, pvt->outbuf + pvt->datalen, pvt->t->buf_size - pvt->datalen);
00262 if (-1 == res) {
00263 if (EWOULDBLOCK == errno) {
00264
00265 return NULL;
00266 } else {
00267 ast_log(LOG_ERROR, "Failed to read from transcoder: %s\n", strerror(errno));
00268 return NULL;
00269 }
00270 } else {
00271 pvt->f.datalen = res;
00272 pvt->f.samples = ztp->required_samples;
00273 pvt->f.frametype = AST_FRAME_VOICE;
00274 pvt->f.subclass = 1 << (pvt->t->dstfmt);
00275 pvt->f.mallocd = 0;
00276 pvt->f.offset = AST_FRIENDLY_OFFSET;
00277 pvt->f.src = pvt->t->name;
00278 pvt->f.data = pvt->outbuf;
00279
00280 pvt->samples = 0;
00281 pvt->datalen = 0;
00282 return ast_frisolate(&pvt->f);
00283 }
00284
00285
00286 return NULL;
00287 }
00288
00289 static int dahdi_decoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00290 {
00291 struct codec_dahdi_pvt *ztp = pvt->pvt;
00292
00293 if (!f->subclass) {
00294
00295 ztp->fake = 2;
00296 pvt->samples = f->samples;
00297 return 0;
00298 }
00299
00300 if (!f->datalen) {
00301 if (f->samples != ztp->required_samples) {
00302 ast_log(LOG_ERROR, "%d != %d %d\n", f->samples, ztp->required_samples, f->datalen);
00303 }
00304 }
00305 dahdi_write_frame(ztp, f->data, f->datalen);
00306 pvt->samples += f->samples;
00307 pvt->datalen = 0;
00308 return -1;
00309 }
00310
00311 static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt)
00312 {
00313 int res;
00314 struct codec_dahdi_pvt *ztp = pvt->pvt;
00315
00316 if (2 == ztp->fake) {
00317 ztp->fake = 1;
00318 pvt->f.frametype = AST_FRAME_VOICE;
00319 pvt->f.subclass = 0;
00320 pvt->f.samples = ztp->required_samples;
00321 pvt->f.data = NULL;
00322 pvt->f.offset = 0;
00323 pvt->f.datalen = 0;
00324 pvt->f.mallocd = 0;
00325 pvt->samples = 0;
00326 return ast_frisolate(&pvt->f);
00327 } else if (1 == ztp->fake) {
00328 pvt->samples = 0;
00329 ztp->fake = 0;
00330 return NULL;
00331 }
00332
00333
00334 if (ztp->softslin) {
00335 res = read(ztp->fd, ztp->ulaw_buffer, sizeof(ztp->ulaw_buffer));
00336 } else {
00337 res = read(ztp->fd, pvt->outbuf + pvt->datalen, pvt->t->buf_size - pvt->datalen);
00338 }
00339
00340 if (-1 == res) {
00341 if (EWOULDBLOCK == errno) {
00342
00343 return NULL;
00344 } else {
00345 ast_log(LOG_ERROR, "Failed to read from transcoder: %s\n", strerror(errno));
00346 return NULL;
00347 }
00348 } else {
00349 if (ztp->softslin) {
00350 ulawtolin(pvt);
00351 pvt->f.datalen = res * 2;
00352 } else {
00353 pvt->f.datalen = res;
00354 }
00355 pvt->datalen = 0;
00356 pvt->f.frametype = AST_FRAME_VOICE;
00357 pvt->f.subclass = 1 << (pvt->t->dstfmt);
00358 pvt->f.mallocd = 0;
00359 pvt->f.offset = AST_FRIENDLY_OFFSET;
00360 pvt->f.src = pvt->t->name;
00361 pvt->f.data = pvt->outbuf;
00362 pvt->f.samples = ztp->required_samples;
00363 pvt->samples = 0;
00364
00365 return ast_frisolate(&pvt->f);
00366 }
00367
00368
00369 return NULL;
00370 }
00371
00372
00373 static void dahdi_destroy(struct ast_trans_pvt *pvt)
00374 {
00375 struct codec_dahdi_pvt *ztp = pvt->pvt;
00376
00377 switch (ztp->fmts.dstfmt) {
00378 case AST_FORMAT_G729A:
00379 case AST_FORMAT_G723_1:
00380 ast_atomic_fetchadd_int(&channels.encoders, -1);
00381 break;
00382 default:
00383 ast_atomic_fetchadd_int(&channels.decoders, -1);
00384 break;
00385 }
00386
00387 close(ztp->fd);
00388 }
00389
00390 static int dahdi_translate(struct ast_trans_pvt *pvt, int dest, int source)
00391 {
00392
00393 int fd;
00394 struct codec_dahdi_pvt *ztp = pvt->pvt;
00395 int flags;
00396 int tried_once = 0;
00397 #ifdef HAVE_ZAPTEL
00398 const char *dev_filename = "/dev/zap/transcode";
00399 #else
00400 const char *dev_filename = "/dev/dahdi/transcode";
00401 #endif
00402
00403 if ((fd = open(dev_filename, O_RDWR)) < 0) {
00404 ast_log(LOG_ERROR, "Failed to open %s: %s\n", dev_filename, strerror(errno));
00405 return -1;
00406 }
00407
00408 ztp->fmts.srcfmt = (1 << source);
00409 ztp->fmts.dstfmt = (1 << dest);
00410
00411 if (option_debug) {
00412 ast_log(LOG_DEBUG, "Opening transcoder channel from %d to %d.\n", source, dest);
00413 }
00414
00415 retry:
00416 if (ioctl(fd, DAHDI_TC_ALLOCATE, &ztp->fmts)) {
00417 if ((ENODEV == errno) && !tried_once) {
00418
00419
00420
00421
00422
00423
00424
00425
00426 if (AST_FORMAT_SLINEAR == ztp->fmts.srcfmt) {
00427 if (option_debug) {
00428 ast_log(LOG_DEBUG, "Using soft_slin support on source\n");
00429 }
00430 ztp->softslin = 1;
00431 ztp->fmts.srcfmt = AST_FORMAT_ULAW;
00432 } else if (AST_FORMAT_SLINEAR == ztp->fmts.dstfmt) {
00433 if (option_debug) {
00434 ast_log(LOG_DEBUG, "Using soft_slin support on destination\n");
00435 }
00436 ztp->softslin = 1;
00437 ztp->fmts.dstfmt = AST_FORMAT_ULAW;
00438 }
00439 tried_once = 1;
00440 goto retry;
00441 }
00442 ast_log(LOG_ERROR, "Unable to attach to transcoder: %s\n", strerror(errno));
00443 close(fd);
00444
00445 return -1;
00446 }
00447
00448 flags = fcntl(fd, F_GETFL);
00449 if (flags > - 1) {
00450 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
00451 ast_log(LOG_WARNING, "Could not set non-block mode!\n");
00452 }
00453
00454 ztp->fd = fd;
00455
00456 ztp->required_samples = ((ztp->fmts.dstfmt|ztp->fmts.srcfmt)&AST_FORMAT_G723_1) ? G723_SAMPLES : G729_SAMPLES;
00457
00458 switch (ztp->fmts.dstfmt) {
00459 case AST_FORMAT_G729A:
00460 ast_atomic_fetchadd_int(&channels.encoders, +1);
00461 break;
00462 case AST_FORMAT_G723_1:
00463 ast_atomic_fetchadd_int(&channels.encoders, +1);
00464 break;
00465 default:
00466 ast_atomic_fetchadd_int(&channels.decoders, +1);
00467 break;
00468 }
00469
00470 return 0;
00471 }
00472
00473 static int dahdi_new(struct ast_trans_pvt *pvt)
00474 {
00475 return dahdi_translate(pvt, pvt->t->dstfmt, pvt->t->srcfmt);
00476 }
00477
00478 static struct ast_frame *fakesrc_sample(void)
00479 {
00480
00481 static struct ast_frame f = {
00482 .frametype = AST_FRAME_VOICE,
00483 .samples = 160,
00484 .src = __PRETTY_FUNCTION__
00485 };
00486
00487 return &f;
00488 }
00489
00490 static int is_encoder(struct translator *zt)
00491 {
00492 if (zt->t.srcfmt&(AST_FORMAT_ULAW|AST_FORMAT_ALAW|AST_FORMAT_SLINEAR)) {
00493 return 1;
00494 } else {
00495 return 0;
00496 }
00497 }
00498
00499 static int register_translator(int dst, int src)
00500 {
00501 struct translator *zt;
00502 int res;
00503
00504 if (!(zt = ast_calloc(1, sizeof(*zt)))) {
00505 return -1;
00506 }
00507
00508 snprintf((char *) (zt->t.name), sizeof(zt->t.name), "zap%sto%s",
00509 ast_getformatname((1 << src)), ast_getformatname((1 << dst)));
00510 zt->t.srcfmt = (1 << src);
00511 zt->t.dstfmt = (1 << dst);
00512 zt->t.buf_size = BUFFER_SIZE;
00513 if (is_encoder(zt)) {
00514 zt->t.framein = dahdi_encoder_framein;
00515 zt->t.frameout = dahdi_encoder_frameout;
00516 #if 0
00517 zt->t.buffer_samples = 0;
00518 #endif
00519 } else {
00520 zt->t.framein = dahdi_decoder_framein;
00521 zt->t.frameout = dahdi_decoder_frameout;
00522 #if 0
00523 if (AST_FORMAT_G723_1 == zt->t.srcfmt) {
00524 zt->t.plc_samples = G723_SAMPLES;
00525 } else {
00526 zt->t.plc_samples = G729_SAMPLES;
00527 }
00528 zt->t.buffer_samples = zt->t.plc_samples * 8;
00529 #endif
00530 }
00531 zt->t.destroy = dahdi_destroy;
00532 zt->t.buffer_samples = 0;
00533 zt->t.newpvt = dahdi_new;
00534 zt->t.sample = fakesrc_sample;
00535 #if 0
00536 zt->t.useplc = global_useplc;
00537 #endif
00538 zt->t.useplc = 0;
00539 zt->t.native_plc = 0;
00540
00541 zt->t.desc_size = sizeof(struct codec_dahdi_pvt);
00542 if ((res = ast_register_translator(&zt->t))) {
00543 free(zt);
00544 return -1;
00545 }
00546
00547 AST_LIST_LOCK(&translators);
00548 AST_LIST_INSERT_HEAD(&translators, zt, entry);
00549 AST_LIST_UNLOCK(&translators);
00550
00551 global_format_map.map[dst][src] = 1;
00552
00553 return res;
00554 }
00555
00556 static void drop_translator(int dst, int src)
00557 {
00558 struct translator *cur;
00559
00560 AST_LIST_LOCK(&translators);
00561 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators, cur, entry) {
00562 if (cur->t.srcfmt != src)
00563 continue;
00564
00565 if (cur->t.dstfmt != dst)
00566 continue;
00567
00568 AST_LIST_REMOVE_CURRENT(&translators, entry);
00569 ast_unregister_translator(&cur->t);
00570 free(cur);
00571 global_format_map.map[dst][src] = 0;
00572 break;
00573 }
00574 AST_LIST_TRAVERSE_SAFE_END;
00575 AST_LIST_UNLOCK(&translators);
00576 }
00577
00578 static void unregister_translators(void)
00579 {
00580 struct translator *cur;
00581
00582 AST_LIST_LOCK(&translators);
00583 while ((cur = AST_LIST_REMOVE_HEAD(&translators, entry))) {
00584 ast_unregister_translator(&cur->t);
00585 free(cur);
00586 }
00587 AST_LIST_UNLOCK(&translators);
00588 }
00589
00590 static void parse_config(void)
00591 {
00592 struct ast_variable *var;
00593 struct ast_config *cfg = ast_config_load("codecs.conf");
00594
00595 if (!cfg)
00596 return;
00597
00598 for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
00599 if (!strcasecmp(var->name, "genericplc")) {
00600 global_useplc = ast_true(var->value);
00601 if (option_verbose > 2)
00602 ast_verbose(VERBOSE_PREFIX_3 "codec_zap: %susing generic PLC\n",
00603 global_useplc ? "" : "not ");
00604 }
00605 }
00606
00607 ast_config_destroy(cfg);
00608 }
00609
00610 static void build_translators(struct format_map *map, unsigned int dstfmts, unsigned int srcfmts)
00611 {
00612 unsigned int src, dst;
00613
00614 for (src = 0; src < 32; src++) {
00615 for (dst = 0; dst < 32; dst++) {
00616 if (!(srcfmts & (1 << src)))
00617 continue;
00618
00619 if (!(dstfmts & (1 << dst)))
00620 continue;
00621
00622 if (global_format_map.map[dst][src])
00623 continue;
00624
00625 if (!register_translator(dst, src))
00626 map->map[dst][src] = 1;
00627 }
00628 }
00629 }
00630
00631 static int find_transcoders(void)
00632 {
00633 struct dahdi_transcoder_info info = { 0, };
00634 struct format_map map = { { { 0 } } };
00635 int fd, res;
00636 unsigned int x, y;
00637
00638 if ((fd = open(DAHDI_FILE_TRANSCODE, O_RDWR)) < 0) {
00639 ast_log(LOG_ERROR, "Failed to open " DAHDI_FILE_TRANSCODE ": %s\n", strerror(errno));
00640 return 0;
00641 }
00642
00643 for (info.tcnum = 0; !(res = ioctl(fd, DAHDI_TC_GETINFO, &info)); info.tcnum++) {
00644 if (option_verbose > 1)
00645 ast_verbose(VERBOSE_PREFIX_2 "Found transcoder '%s'.\n", info.name);
00646
00647
00648
00649
00650
00651
00652
00653 if (info.dstfmts & (AST_FORMAT_ULAW | AST_FORMAT_ALAW)) {
00654 info.dstfmts |= AST_FORMAT_SLINEAR;
00655 info.dstfmts &= ~(AST_FORMAT_ULAW | AST_FORMAT_ALAW);
00656 }
00657 if (info.srcfmts & (AST_FORMAT_ULAW | AST_FORMAT_ALAW)) {
00658 info.srcfmts |= AST_FORMAT_SLINEAR;
00659 info.srcfmts &= ~(AST_FORMAT_ULAW | AST_FORMAT_ALAW);
00660 }
00661
00662 build_translators(&map, info.dstfmts, info.srcfmts);
00663 ast_atomic_fetchadd_int(&channels.total, info.numchannels / 2);
00664
00665 }
00666
00667 close(fd);
00668
00669 if (!info.tcnum && (option_verbose > 1))
00670 ast_verbose(VERBOSE_PREFIX_2 "No hardware transcoders found.\n");
00671
00672 for (x = 0; x < 32; x++) {
00673 for (y = 0; y < 32; y++) {
00674 if (!map.map[x][y] && global_format_map.map[x][y])
00675 drop_translator(x, y);
00676 }
00677 }
00678
00679 return 0;
00680 }
00681
00682 static int reload(void)
00683 {
00684 struct translator *cur;
00685
00686 parse_config();
00687
00688 AST_LIST_LOCK(&translators);
00689 AST_LIST_TRAVERSE(&translators, cur, entry)
00690 cur->t.useplc = global_useplc;
00691 AST_LIST_UNLOCK(&translators);
00692
00693 return 0;
00694 }
00695
00696 static int unload_module(void)
00697 {
00698 ast_cli_unregister_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00699 unregister_translators();
00700
00701 return 0;
00702 }
00703
00704 static int load_module(void)
00705 {
00706 ast_ulaw_init();
00707 parse_config();
00708 find_transcoders();
00709 ast_cli_register_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00710
00711 return 0;
00712 }
00713
00714 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Generic DAHDI Transcoder Codec Translator",
00715 .load = load_module,
00716 .unload = unload_module,
00717 .reload = reload,
00718 );