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