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: 176805 $")
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 struct dahdi_transcoder_formats fmts;
00089 unsigned int softslin:1;
00090 unsigned int fake:2;
00091 uint16_t required_samples;
00092 uint16_t samples_in_buffer;
00093 uint8_t ulaw_buffer[1024];
00094 };
00095
00096
00097 static int ulawtolin(struct ast_trans_pvt *pvt)
00098 {
00099 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00100 int i = dahdip->required_samples;
00101 uint8_t *src = &dahdip->ulaw_buffer[0];
00102 int16_t *dst = (int16_t *)pvt->outbuf + pvt->datalen;
00103
00104
00105 while (i--) {
00106 *dst++ = AST_MULAW(*src++);
00107 }
00108
00109 return 0;
00110 }
00111
00112
00113 static int lintoulaw(struct ast_trans_pvt *pvt, struct ast_frame *f)
00114 {
00115 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00116 int i = f->samples;
00117 uint8_t *dst = &dahdip->ulaw_buffer[dahdip->samples_in_buffer];
00118 int16_t *src = f->data;
00119
00120 if (dahdip->samples_in_buffer + i > sizeof(dahdip->ulaw_buffer)) {
00121 ast_log(LOG_ERROR, "Out of buffer space!\n");
00122 return -i;
00123 }
00124
00125 while (i--) {
00126 *dst++ = AST_LIN2MU(*src++);
00127 }
00128
00129 dahdip->samples_in_buffer += f->samples;
00130 return 0;
00131 }
00132
00133 static char *handle_cli_transcoder_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00134 {
00135 struct channel_usage copy;
00136
00137 switch (cmd) {
00138 case CLI_INIT:
00139 e->command = "transcoder show";
00140 e->usage =
00141 "Usage: transcoder show\n"
00142 " Displays channel utilization of DAHDI transcoder(s).\n";
00143 return NULL;
00144 case CLI_GENERATE:
00145 return NULL;
00146 }
00147
00148 if (a->argc != 2)
00149 return CLI_SHOWUSAGE;
00150
00151 copy = channels;
00152
00153 if (copy.total == 0)
00154 ast_cli(a->fd, "No DAHDI transcoders found.\n");
00155 else
00156 ast_cli(a->fd, "%d/%d encoders/decoders of %d channels are in use.\n", copy.encoders, copy.decoders, copy.total);
00157
00158 return CLI_SUCCESS;
00159 }
00160
00161 static void dahdi_write_frame(struct codec_dahdi_pvt *dahdip, const uint8_t *buffer, const ssize_t count)
00162 {
00163 int res;
00164 struct pollfd p = {0};
00165 if (!count) return;
00166 res = write(dahdip->fd, buffer, count);
00167 if (option_verbose > 10) {
00168 if (-1 == res) {
00169 ast_log(LOG_ERROR, "Failed to write to transcoder: %s\n", strerror(errno));
00170 }
00171 if (count != res) {
00172 ast_log(LOG_ERROR, "Requested write of %zd bytes, but only wrote %d bytes.\n", count, res);
00173 }
00174 }
00175 p.fd = dahdip->fd;
00176 p.events = POLLOUT;
00177 res = poll(&p, 1, 50);
00178 }
00179
00180 static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00181 {
00182 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00183
00184 if (!f->subclass) {
00185
00186 dahdip->fake = 2;
00187 pvt->samples = f->samples;
00188 return 0;
00189 }
00190
00191
00192
00193 if (dahdip->softslin) {
00194 if (lintoulaw(pvt, f)) {
00195 return -1;
00196 }
00197 } else {
00198
00199
00200
00201
00202 if (dahdip->samples_in_buffer + f->samples > sizeof(dahdip->ulaw_buffer)) {
00203 ast_log(LOG_ERROR, "Out of buffer space.\n");
00204 return -1;
00205 }
00206 memcpy(&dahdip->ulaw_buffer[dahdip->samples_in_buffer], f->data, f->samples);
00207 dahdip->samples_in_buffer += f->samples;
00208 }
00209
00210 while (dahdip->samples_in_buffer > dahdip->required_samples) {
00211 dahdi_write_frame(dahdip, dahdip->ulaw_buffer, dahdip->required_samples);
00212 dahdip->samples_in_buffer -= dahdip->required_samples;
00213 if (dahdip->samples_in_buffer) {
00214
00215 memmove(dahdip->ulaw_buffer, &dahdip->ulaw_buffer[dahdip->required_samples],
00216 dahdip->samples_in_buffer);
00217 }
00218 }
00219 pvt->samples += f->samples;
00220 pvt->datalen = 0;
00221 return -1;
00222 }
00223
00224 static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt)
00225 {
00226 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00227 int res;
00228
00229 if (2 == dahdip->fake) {
00230 dahdip->fake = 1;
00231 pvt->f.frametype = AST_FRAME_VOICE;
00232 pvt->f.subclass = 0;
00233 pvt->f.samples = dahdip->required_samples;
00234 pvt->f.data = NULL;
00235 pvt->f.offset = 0;
00236 pvt->f.datalen = 0;
00237 pvt->f.mallocd = 0;
00238 ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
00239 pvt->samples = 0;
00240
00241 return &pvt->f;
00242
00243 } else if (1 == dahdip->fake) {
00244 dahdip->fake = 0;
00245 return NULL;
00246 }
00247
00248 res = read(dahdip->fd, pvt->outbuf + pvt->datalen, pvt->t->buf_size - pvt->datalen);
00249 if (-1 == res) {
00250 if (EWOULDBLOCK == errno) {
00251
00252 return NULL;
00253 } else {
00254 ast_log(LOG_ERROR, "Failed to read from transcoder: %s\n", strerror(errno));
00255 return NULL;
00256 }
00257 } else {
00258 pvt->f.datalen = res;
00259 pvt->f.samples = dahdip->required_samples;
00260 pvt->f.frametype = AST_FRAME_VOICE;
00261 pvt->f.subclass = 1 << (pvt->t->dstfmt);
00262 pvt->f.mallocd = 0;
00263 pvt->f.offset = AST_FRIENDLY_OFFSET;
00264 pvt->f.src = pvt->t->name;
00265 pvt->f.data = pvt->outbuf;
00266 ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
00267
00268 pvt->samples = 0;
00269 pvt->datalen = 0;
00270 return &pvt->f;
00271 }
00272
00273
00274 return NULL;
00275 }
00276
00277 static int dahdi_decoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00278 {
00279 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00280
00281 if (!f->subclass) {
00282
00283 dahdip->fake = 2;
00284 pvt->samples = f->samples;
00285 return 0;
00286 }
00287
00288 if (!f->datalen) {
00289 if (f->samples != dahdip->required_samples) {
00290 ast_log(LOG_ERROR, "%d != %d %d\n", f->samples, dahdip->required_samples, f->datalen);
00291 }
00292 }
00293 dahdi_write_frame(dahdip, f->data, f->datalen);
00294 pvt->samples += f->samples;
00295 pvt->datalen = 0;
00296 return -1;
00297 }
00298
00299 static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt)
00300 {
00301 int res;
00302 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00303
00304 if (2 == dahdip->fake) {
00305 dahdip->fake = 1;
00306 pvt->f.frametype = AST_FRAME_VOICE;
00307 pvt->f.subclass = 0;
00308 pvt->f.samples = dahdip->required_samples;
00309 pvt->f.data = NULL;
00310 pvt->f.offset = 0;
00311 pvt->f.datalen = 0;
00312 pvt->f.mallocd = 0;
00313 ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
00314 pvt->samples = 0;
00315 return &pvt->f;
00316 } else if (1 == dahdip->fake) {
00317 pvt->samples = 0;
00318 dahdip->fake = 0;
00319 return NULL;
00320 }
00321
00322
00323 if (dahdip->softslin) {
00324 res = read(dahdip->fd, dahdip->ulaw_buffer, sizeof(dahdip->ulaw_buffer));
00325 } else {
00326 res = read(dahdip->fd, pvt->outbuf + pvt->datalen, pvt->t->buf_size - pvt->datalen);
00327 }
00328
00329 if (-1 == res) {
00330 if (EWOULDBLOCK == errno) {
00331
00332 return NULL;
00333 } else {
00334 ast_log(LOG_ERROR, "Failed to read from transcoder: %s\n", strerror(errno));
00335 return NULL;
00336 }
00337 } else {
00338 if (dahdip->softslin) {
00339 ulawtolin(pvt);
00340 pvt->f.datalen = res * 2;
00341 } else {
00342 pvt->f.datalen = res;
00343 }
00344 pvt->datalen = 0;
00345 pvt->f.frametype = AST_FRAME_VOICE;
00346 pvt->f.subclass = 1 << (pvt->t->dstfmt);
00347 pvt->f.mallocd = 0;
00348 pvt->f.offset = AST_FRIENDLY_OFFSET;
00349 pvt->f.src = pvt->t->name;
00350 pvt->f.data = pvt->outbuf;
00351 pvt->f.samples = dahdip->required_samples;
00352 ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
00353 pvt->samples = 0;
00354
00355 return &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_log(LOG_DEBUG, "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_log(LOG_DEBUG, "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_log(LOG_DEBUG, "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 );