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