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