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