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