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: 224933 $")
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 pvt->samples = 0;
00239
00240 return ast_frisolate(&pvt->f);
00241
00242 } else if (1 == dahdip->fake) {
00243 dahdip->fake = 0;
00244 return NULL;
00245 }
00246
00247 res = read(dahdip->fd, pvt->outbuf + pvt->datalen, pvt->t->buf_size - pvt->datalen);
00248 if (-1 == res) {
00249 if (EWOULDBLOCK == errno) {
00250
00251 return NULL;
00252 } else {
00253 ast_log(LOG_ERROR, "Failed to read from transcoder: %s\n", strerror(errno));
00254 return NULL;
00255 }
00256 } else {
00257 pvt->f.datalen = res;
00258 pvt->f.samples = dahdip->required_samples;
00259 pvt->f.frametype = AST_FRAME_VOICE;
00260 pvt->f.subclass = 1 << (pvt->t->dstfmt);
00261 pvt->f.mallocd = 0;
00262 pvt->f.offset = AST_FRIENDLY_OFFSET;
00263 pvt->f.src = pvt->t->name;
00264 pvt->f.data = pvt->outbuf;
00265
00266 pvt->samples = 0;
00267 pvt->datalen = 0;
00268 return ast_frisolate(&pvt->f);
00269 }
00270
00271
00272 return NULL;
00273 }
00274
00275 static int dahdi_decoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00276 {
00277 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00278
00279 if (!f->subclass) {
00280
00281 dahdip->fake = 2;
00282 pvt->samples = f->samples;
00283 return 0;
00284 }
00285
00286 if (!f->datalen) {
00287 if (f->samples != dahdip->required_samples) {
00288 ast_log(LOG_ERROR, "%d != %d %d\n", f->samples, dahdip->required_samples, f->datalen);
00289 }
00290 }
00291 dahdi_write_frame(dahdip, f->data, f->datalen);
00292 pvt->samples += f->samples;
00293 pvt->datalen = 0;
00294 return -1;
00295 }
00296
00297 static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt)
00298 {
00299 int res;
00300 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00301
00302 if (2 == dahdip->fake) {
00303 dahdip->fake = 1;
00304 pvt->f.frametype = AST_FRAME_VOICE;
00305 pvt->f.subclass = 0;
00306 pvt->f.samples = dahdip->required_samples;
00307 pvt->f.data = NULL;
00308 pvt->f.offset = 0;
00309 pvt->f.datalen = 0;
00310 pvt->f.mallocd = 0;
00311 pvt->samples = 0;
00312 return ast_frisolate(&pvt->f);
00313 } else if (1 == dahdip->fake) {
00314 pvt->samples = 0;
00315 dahdip->fake = 0;
00316 return NULL;
00317 }
00318
00319
00320 if (dahdip->softslin) {
00321 res = read(dahdip->fd, dahdip->ulaw_buffer, sizeof(dahdip->ulaw_buffer));
00322 } else {
00323 res = read(dahdip->fd, pvt->outbuf + pvt->datalen, pvt->t->buf_size - pvt->datalen);
00324 }
00325
00326 if (-1 == res) {
00327 if (EWOULDBLOCK == errno) {
00328
00329 return NULL;
00330 } else {
00331 ast_log(LOG_ERROR, "Failed to read from transcoder: %s\n", strerror(errno));
00332 return NULL;
00333 }
00334 } else {
00335 if (dahdip->softslin) {
00336 ulawtolin(pvt);
00337 pvt->f.datalen = res * 2;
00338 } else {
00339 pvt->f.datalen = res;
00340 }
00341 pvt->datalen = 0;
00342 pvt->f.frametype = AST_FRAME_VOICE;
00343 pvt->f.subclass = 1 << (pvt->t->dstfmt);
00344 pvt->f.mallocd = 0;
00345 pvt->f.offset = AST_FRIENDLY_OFFSET;
00346 pvt->f.src = pvt->t->name;
00347 pvt->f.data = pvt->outbuf;
00348 pvt->f.samples = dahdip->required_samples;
00349 pvt->samples = 0;
00350
00351 return ast_frisolate(&pvt->f);
00352 }
00353
00354
00355 return NULL;
00356 }
00357
00358
00359 static void dahdi_destroy(struct ast_trans_pvt *pvt)
00360 {
00361 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00362
00363 switch (dahdip->fmts.dstfmt) {
00364 case AST_FORMAT_G729A:
00365 case AST_FORMAT_G723_1:
00366 ast_atomic_fetchadd_int(&channels.encoders, -1);
00367 break;
00368 default:
00369 ast_atomic_fetchadd_int(&channels.decoders, -1);
00370 break;
00371 }
00372
00373 close(dahdip->fd);
00374 }
00375
00376 static int dahdi_translate(struct ast_trans_pvt *pvt, int dest, int source)
00377 {
00378
00379 int fd;
00380 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00381 int flags;
00382 int tried_once = 0;
00383 const char *dev_filename = "/dev/dahdi/transcode";
00384
00385 if ((fd = open(dev_filename, O_RDWR)) < 0) {
00386 ast_log(LOG_ERROR, "Failed to open %s: %s\n", dev_filename, strerror(errno));
00387 return -1;
00388 }
00389
00390 dahdip->fmts.srcfmt = (1 << source);
00391 dahdip->fmts.dstfmt = (1 << dest);
00392
00393 ast_debug(1, "Opening transcoder channel from %d to %d.\n", source, dest);
00394
00395 retry:
00396 if (ioctl(fd, DAHDI_TC_ALLOCATE, &dahdip->fmts)) {
00397 if ((ENODEV == errno) && !tried_once) {
00398
00399
00400
00401
00402
00403
00404
00405
00406 if (AST_FORMAT_SLINEAR == dahdip->fmts.srcfmt) {
00407 ast_debug(1, "Using soft_slin support on source\n");
00408 dahdip->softslin = 1;
00409 dahdip->fmts.srcfmt = AST_FORMAT_ULAW;
00410 } else if (AST_FORMAT_SLINEAR == dahdip->fmts.dstfmt) {
00411 ast_debug(1, "Using soft_slin support on destination\n");
00412 dahdip->softslin = 1;
00413 dahdip->fmts.dstfmt = AST_FORMAT_ULAW;
00414 }
00415 tried_once = 1;
00416 goto retry;
00417 }
00418 ast_log(LOG_ERROR, "Unable to attach to transcoder: %s\n", strerror(errno));
00419 close(fd);
00420
00421 return -1;
00422 }
00423
00424 flags = fcntl(fd, F_GETFL);
00425 if (flags > - 1) {
00426 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
00427 ast_log(LOG_WARNING, "Could not set non-block mode!\n");
00428 }
00429
00430 dahdip->fd = fd;
00431
00432 dahdip->required_samples = ((dahdip->fmts.dstfmt|dahdip->fmts.srcfmt)&AST_FORMAT_G723_1) ? G723_SAMPLES : G729_SAMPLES;
00433
00434 switch (dahdip->fmts.dstfmt) {
00435 case AST_FORMAT_G729A:
00436 ast_atomic_fetchadd_int(&channels.encoders, +1);
00437 break;
00438 case AST_FORMAT_G723_1:
00439 ast_atomic_fetchadd_int(&channels.encoders, +1);
00440 break;
00441 default:
00442 ast_atomic_fetchadd_int(&channels.decoders, +1);
00443 break;
00444 }
00445
00446 return 0;
00447 }
00448
00449 static int dahdi_new(struct ast_trans_pvt *pvt)
00450 {
00451 return dahdi_translate(pvt, pvt->t->dstfmt, pvt->t->srcfmt);
00452 }
00453
00454 static struct ast_frame *fakesrc_sample(void)
00455 {
00456
00457 static struct ast_frame f = {
00458 .frametype = AST_FRAME_VOICE,
00459 .samples = 160,
00460 .src = __PRETTY_FUNCTION__
00461 };
00462
00463 return &f;
00464 }
00465
00466 static int is_encoder(struct translator *zt)
00467 {
00468 if (zt->t.srcfmt&(AST_FORMAT_ULAW|AST_FORMAT_ALAW|AST_FORMAT_SLINEAR)) {
00469 return 1;
00470 } else {
00471 return 0;
00472 }
00473 }
00474
00475 static int register_translator(int dst, int src)
00476 {
00477 struct translator *zt;
00478 int res;
00479
00480 if (!(zt = ast_calloc(1, sizeof(*zt)))) {
00481 return -1;
00482 }
00483
00484 snprintf((char *) (zt->t.name), sizeof(zt->t.name), "zap%sto%s",
00485 ast_getformatname((1 << src)), ast_getformatname((1 << dst)));
00486 zt->t.srcfmt = (1 << src);
00487 zt->t.dstfmt = (1 << dst);
00488 zt->t.buf_size = BUFFER_SIZE;
00489 if (is_encoder(zt)) {
00490 zt->t.framein = dahdi_encoder_framein;
00491 zt->t.frameout = dahdi_encoder_frameout;
00492 #if 0
00493 zt->t.buffer_samples = 0;
00494 #endif
00495 } else {
00496 zt->t.framein = dahdi_decoder_framein;
00497 zt->t.frameout = dahdi_decoder_frameout;
00498 #if 0
00499 if (AST_FORMAT_G723_1 == zt->t.srcfmt) {
00500 zt->t.plc_samples = G723_SAMPLES;
00501 } else {
00502 zt->t.plc_samples = G729_SAMPLES;
00503 }
00504 zt->t.buffer_samples = zt->t.plc_samples * 8;
00505 #endif
00506 }
00507 zt->t.destroy = dahdi_destroy;
00508 zt->t.buffer_samples = 0;
00509 zt->t.newpvt = dahdi_new;
00510 zt->t.sample = fakesrc_sample;
00511 #if 0
00512 zt->t.useplc = global_useplc;
00513 #endif
00514 zt->t.useplc = 0;
00515 zt->t.native_plc = 0;
00516
00517 zt->t.desc_size = sizeof(struct codec_dahdi_pvt);
00518 if ((res = ast_register_translator(&zt->t))) {
00519 ast_free(zt);
00520 return -1;
00521 }
00522
00523 AST_LIST_LOCK(&translators);
00524 AST_LIST_INSERT_HEAD(&translators, zt, entry);
00525 AST_LIST_UNLOCK(&translators);
00526
00527 global_format_map.map[dst][src] = 1;
00528
00529 return res;
00530 }
00531
00532 static void drop_translator(int dst, int src)
00533 {
00534 struct translator *cur;
00535
00536 AST_LIST_LOCK(&translators);
00537 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators, cur, entry) {
00538 if (cur->t.srcfmt != src)
00539 continue;
00540
00541 if (cur->t.dstfmt != dst)
00542 continue;
00543
00544 AST_LIST_REMOVE_CURRENT(entry);
00545 ast_unregister_translator(&cur->t);
00546 ast_free(cur);
00547 global_format_map.map[dst][src] = 0;
00548 break;
00549 }
00550 AST_LIST_TRAVERSE_SAFE_END;
00551 AST_LIST_UNLOCK(&translators);
00552 }
00553
00554 static void unregister_translators(void)
00555 {
00556 struct translator *cur;
00557
00558 AST_LIST_LOCK(&translators);
00559 while ((cur = AST_LIST_REMOVE_HEAD(&translators, entry))) {
00560 ast_unregister_translator(&cur->t);
00561 ast_free(cur);
00562 }
00563 AST_LIST_UNLOCK(&translators);
00564 }
00565
00566 static int parse_config(int reload)
00567 {
00568 struct ast_variable *var;
00569 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00570 struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
00571
00572 if (cfg == NULL)
00573 return 0;
00574 if (cfg == CONFIG_STATUS_FILEUNCHANGED)
00575 return 0;
00576
00577 for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
00578 if (!strcasecmp(var->name, "genericplc")) {
00579 global_useplc = ast_true(var->value);
00580 ast_verb(3, "codec_dahdi: %susing generic PLC\n",
00581 global_useplc ? "" : "not ");
00582 }
00583 }
00584
00585 ast_config_destroy(cfg);
00586 return 0;
00587 }
00588
00589 static void build_translators(struct format_map *map, unsigned int dstfmts, unsigned int srcfmts)
00590 {
00591 unsigned int src, dst;
00592
00593 for (src = 0; src < 32; src++) {
00594 for (dst = 0; dst < 32; dst++) {
00595 if (!(srcfmts & (1 << src)))
00596 continue;
00597
00598 if (!(dstfmts & (1 << dst)))
00599 continue;
00600
00601 if (global_format_map.map[dst][src])
00602 continue;
00603
00604 if (!register_translator(dst, src))
00605 map->map[dst][src] = 1;
00606 }
00607 }
00608 }
00609
00610 static int find_transcoders(void)
00611 {
00612 struct dahdi_transcoder_info info = { 0, };
00613 struct format_map map = { { { 0 } } };
00614 int fd, res;
00615 unsigned int x, y;
00616
00617 if ((fd = open("/dev/dahdi/transcode", O_RDWR)) < 0) {
00618 ast_log(LOG_ERROR, "Failed to open /dev/dahdi/transcode: %s\n", strerror(errno));
00619 return 0;
00620 }
00621
00622 for (info.tcnum = 0; !(res = ioctl(fd, DAHDI_TC_GETINFO, &info)); info.tcnum++) {
00623 if (option_verbose > 1)
00624 ast_verbose(VERBOSE_PREFIX_2 "Found transcoder '%s'.\n", info.name);
00625
00626
00627
00628
00629
00630
00631
00632 if (info.dstfmts & (AST_FORMAT_ULAW | AST_FORMAT_ALAW)) {
00633 info.dstfmts |= AST_FORMAT_SLINEAR;
00634 info.dstfmts &= ~(AST_FORMAT_ULAW | AST_FORMAT_ALAW);
00635 }
00636 if (info.srcfmts & (AST_FORMAT_ULAW | AST_FORMAT_ALAW)) {
00637 info.srcfmts |= AST_FORMAT_SLINEAR;
00638 info.srcfmts &= ~(AST_FORMAT_ULAW | AST_FORMAT_ALAW);
00639 }
00640
00641 build_translators(&map, info.dstfmts, info.srcfmts);
00642 ast_atomic_fetchadd_int(&channels.total, info.numchannels / 2);
00643
00644 }
00645
00646 close(fd);
00647
00648 if (!info.tcnum && (option_verbose > 1))
00649 ast_verbose(VERBOSE_PREFIX_2 "No hardware transcoders found.\n");
00650
00651 for (x = 0; x < 32; x++) {
00652 for (y = 0; y < 32; y++) {
00653 if (!map.map[x][y] && global_format_map.map[x][y])
00654 drop_translator(x, y);
00655 }
00656 }
00657
00658 return 0;
00659 }
00660
00661 static int reload(void)
00662 {
00663 struct translator *cur;
00664
00665 if (parse_config(1))
00666 return AST_MODULE_LOAD_DECLINE;
00667
00668 AST_LIST_LOCK(&translators);
00669 AST_LIST_TRAVERSE(&translators, cur, entry)
00670 cur->t.useplc = global_useplc;
00671 AST_LIST_UNLOCK(&translators);
00672
00673 return AST_MODULE_LOAD_SUCCESS;
00674 }
00675
00676 static int unload_module(void)
00677 {
00678 ast_cli_unregister_multiple(cli, ARRAY_LEN(cli));
00679 unregister_translators();
00680
00681 return 0;
00682 }
00683
00684 static int load_module(void)
00685 {
00686 ast_ulaw_init();
00687 if (parse_config(0))
00688 return AST_MODULE_LOAD_DECLINE;
00689 find_transcoders();
00690 ast_cli_register_multiple(cli, ARRAY_LEN(cli));
00691 return AST_MODULE_LOAD_SUCCESS;
00692 }
00693
00694 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Generic DAHDI Transcoder Codec Translator",
00695 .load = load_module,
00696 .unload = unload_module,
00697 .reload = reload,
00698 );