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: 365989 $")
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 #define ULAW_SAMPLES 160
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 uint16_t samples_written_to_hardware;
00094 uint8_t ulaw_buffer[1024];
00095 };
00096
00097
00098 static int ulawtolin(struct ast_trans_pvt *pvt, int samples)
00099 {
00100 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00101 int i = samples;
00102 uint8_t *src = &dahdip->ulaw_buffer[0];
00103 int16_t *dst = pvt->outbuf.i16 + pvt->datalen;
00104
00105
00106 while (i--) {
00107 *dst++ = AST_MULAW(*src++);
00108 }
00109
00110 return 0;
00111 }
00112
00113
00114 static int lintoulaw(struct ast_trans_pvt *pvt, struct ast_frame *f)
00115 {
00116 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00117 int i = f->samples;
00118 uint8_t *dst = &dahdip->ulaw_buffer[dahdip->samples_in_buffer];
00119 int16_t *src = f->data.ptr;
00120
00121 if (dahdip->samples_in_buffer + i > sizeof(dahdip->ulaw_buffer)) {
00122 ast_log(LOG_ERROR, "Out of buffer space!\n");
00123 return -i;
00124 }
00125
00126 while (i--) {
00127 *dst++ = AST_LIN2MU(*src++);
00128 }
00129
00130 dahdip->samples_in_buffer += f->samples;
00131 return 0;
00132 }
00133
00134 static char *handle_cli_transcoder_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00135 {
00136 struct channel_usage copy;
00137
00138 switch (cmd) {
00139 case CLI_INIT:
00140 e->command = "transcoder show";
00141 e->usage =
00142 "Usage: transcoder show\n"
00143 " Displays channel utilization of DAHDI transcoder(s).\n";
00144 return NULL;
00145 case CLI_GENERATE:
00146 return NULL;
00147 }
00148
00149 if (a->argc != 2)
00150 return CLI_SHOWUSAGE;
00151
00152 copy = channels;
00153
00154 if (copy.total == 0)
00155 ast_cli(a->fd, "No DAHDI transcoders found.\n");
00156 else
00157 ast_cli(a->fd, "%d/%d encoders/decoders of %d channels are in use.\n", copy.encoders, copy.decoders, copy.total);
00158
00159 return CLI_SUCCESS;
00160 }
00161
00162 static void dahdi_write_frame(struct codec_dahdi_pvt *dahdip, const uint8_t *buffer, const ssize_t count)
00163 {
00164 int res;
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 }
00176
00177 static int dahdi_encoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00178 {
00179 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00180
00181 if (!f->subclass.codec) {
00182
00183 dahdip->fake = 2;
00184 pvt->samples = f->samples;
00185 return 0;
00186 }
00187
00188
00189
00190 if (dahdip->softslin) {
00191 if (lintoulaw(pvt, f)) {
00192 return -1;
00193 }
00194 } else {
00195
00196
00197
00198
00199 if (dahdip->samples_in_buffer + f->samples > sizeof(dahdip->ulaw_buffer)) {
00200 ast_log(LOG_ERROR, "Out of buffer space.\n");
00201 return -1;
00202 }
00203 memcpy(&dahdip->ulaw_buffer[dahdip->samples_in_buffer], f->data.ptr, f->samples);
00204 dahdip->samples_in_buffer += f->samples;
00205 }
00206
00207 while (dahdip->samples_in_buffer >= dahdip->required_samples) {
00208 dahdi_write_frame(dahdip, dahdip->ulaw_buffer, dahdip->required_samples);
00209 dahdip->samples_written_to_hardware += 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 void dahdi_wait_for_packet(int fd)
00223 {
00224 struct pollfd p = {0};
00225 p.fd = fd;
00226 p.events = POLLIN;
00227 poll(&p, 1, 10);
00228 }
00229
00230 static struct ast_frame *dahdi_encoder_frameout(struct ast_trans_pvt *pvt)
00231 {
00232 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00233 int res;
00234
00235 if (2 == dahdip->fake) {
00236 dahdip->fake = 1;
00237 pvt->f.frametype = AST_FRAME_VOICE;
00238 pvt->f.subclass.codec = 0;
00239 pvt->f.samples = dahdip->required_samples;
00240 pvt->f.data.ptr = NULL;
00241 pvt->f.offset = 0;
00242 pvt->f.datalen = 0;
00243 pvt->f.mallocd = 0;
00244 pvt->samples = 0;
00245
00246 return ast_frisolate(&pvt->f);
00247
00248 } else if (1 == dahdip->fake) {
00249 dahdip->fake = 0;
00250 return NULL;
00251 }
00252
00253 if (dahdip->samples_written_to_hardware >= dahdip->required_samples) {
00254 dahdi_wait_for_packet(dahdip->fd);
00255 }
00256
00257 res = read(dahdip->fd, pvt->outbuf.c + pvt->datalen, pvt->t->buf_size - pvt->datalen);
00258 if (-1 == res) {
00259 if (EWOULDBLOCK == errno) {
00260
00261 return NULL;
00262 } else {
00263 ast_log(LOG_ERROR, "Failed to read from transcoder: %s\n", strerror(errno));
00264 return NULL;
00265 }
00266 } else {
00267 pvt->f.datalen = res;
00268 pvt->f.frametype = AST_FRAME_VOICE;
00269 pvt->f.subclass.codec = 1 << (pvt->t->dstfmt);
00270 pvt->f.mallocd = 0;
00271 pvt->f.offset = AST_FRIENDLY_OFFSET;
00272 pvt->f.src = pvt->t->name;
00273 pvt->f.data.ptr = pvt->outbuf.c;
00274 pvt->f.samples = ast_codec_get_samples(&pvt->f);
00275
00276 dahdip->samples_written_to_hardware =
00277 (dahdip->samples_written_to_hardware >= pvt->f.samples) ?
00278 dahdip->samples_written_to_hardware - pvt->f.samples : 0;
00279
00280 pvt->samples = 0;
00281 pvt->datalen = 0;
00282 return ast_frisolate(&pvt->f);
00283 }
00284
00285
00286 return NULL;
00287 }
00288
00289 static int dahdi_decoder_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00290 {
00291 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00292
00293 if (!f->subclass.codec) {
00294
00295 dahdip->fake = 2;
00296 pvt->samples = f->samples;
00297 return 0;
00298 }
00299
00300 if (!f->datalen) {
00301 if (f->samples != dahdip->required_samples) {
00302 ast_log(LOG_ERROR, "%d != %d %d\n", f->samples, dahdip->required_samples, f->datalen);
00303 }
00304 }
00305 dahdi_write_frame(dahdip, f->data.ptr, f->datalen);
00306 dahdip->samples_written_to_hardware += f->samples;
00307 pvt->samples += f->samples;
00308 pvt->datalen = 0;
00309 return -1;
00310 }
00311
00312 static struct ast_frame *dahdi_decoder_frameout(struct ast_trans_pvt *pvt)
00313 {
00314 int res;
00315 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00316
00317 if (2 == dahdip->fake) {
00318 dahdip->fake = 1;
00319 pvt->f.frametype = AST_FRAME_VOICE;
00320 pvt->f.subclass.codec = 0;
00321 pvt->f.samples = dahdip->required_samples;
00322 pvt->f.data.ptr = NULL;
00323 pvt->f.offset = 0;
00324 pvt->f.datalen = 0;
00325 pvt->f.mallocd = 0;
00326 pvt->samples = 0;
00327 return ast_frisolate(&pvt->f);
00328 } else if (1 == dahdip->fake) {
00329 pvt->samples = 0;
00330 dahdip->fake = 0;
00331 return NULL;
00332 }
00333
00334 if (dahdip->samples_written_to_hardware >= ULAW_SAMPLES) {
00335 dahdi_wait_for_packet(dahdip->fd);
00336 }
00337
00338
00339 if (dahdip->softslin) {
00340 res = read(dahdip->fd, dahdip->ulaw_buffer, sizeof(dahdip->ulaw_buffer));
00341 } else {
00342 res = read(dahdip->fd, pvt->outbuf.c + pvt->datalen, pvt->t->buf_size - pvt->datalen);
00343 }
00344
00345 if (-1 == res) {
00346 if (EWOULDBLOCK == errno) {
00347
00348 return NULL;
00349 } else {
00350 ast_log(LOG_ERROR, "Failed to read from transcoder: %s\n", strerror(errno));
00351 return NULL;
00352 }
00353 } else {
00354 if (dahdip->softslin) {
00355 ulawtolin(pvt, res);
00356 pvt->f.datalen = res * 2;
00357 } else {
00358 pvt->f.datalen = res;
00359 }
00360 pvt->datalen = 0;
00361 pvt->f.frametype = AST_FRAME_VOICE;
00362 pvt->f.subclass.codec = 1 << (pvt->t->dstfmt);
00363 pvt->f.mallocd = 0;
00364 pvt->f.offset = AST_FRIENDLY_OFFSET;
00365 pvt->f.src = pvt->t->name;
00366 pvt->f.data.ptr = pvt->outbuf.c;
00367 pvt->f.samples = res;
00368 pvt->samples = 0;
00369 dahdip->samples_written_to_hardware =
00370 (dahdip->samples_written_to_hardware >= res) ?
00371 dahdip->samples_written_to_hardware - res : 0;
00372
00373 return ast_frisolate(&pvt->f);
00374 }
00375
00376
00377 return NULL;
00378 }
00379
00380
00381 static void dahdi_destroy(struct ast_trans_pvt *pvt)
00382 {
00383 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00384
00385 switch (dahdip->fmts.dstfmt) {
00386 case AST_FORMAT_G729A:
00387 case AST_FORMAT_G723_1:
00388 ast_atomic_fetchadd_int(&channels.encoders, -1);
00389 break;
00390 default:
00391 ast_atomic_fetchadd_int(&channels.decoders, -1);
00392 break;
00393 }
00394
00395 close(dahdip->fd);
00396 }
00397
00398 static int dahdi_translate(struct ast_trans_pvt *pvt, int dest, int source)
00399 {
00400
00401 int fd;
00402 struct codec_dahdi_pvt *dahdip = pvt->pvt;
00403 int flags;
00404 int tried_once = 0;
00405 const char *dev_filename = "/dev/dahdi/transcode";
00406
00407 if ((fd = open(dev_filename, O_RDWR)) < 0) {
00408 ast_log(LOG_ERROR, "Failed to open %s: %s\n", dev_filename, strerror(errno));
00409 return -1;
00410 }
00411
00412 dahdip->fmts.srcfmt = (1 << source);
00413 dahdip->fmts.dstfmt = (1 << dest);
00414
00415 ast_debug(1, "Opening transcoder channel from %d to %d.\n", source, dest);
00416
00417 retry:
00418 if (ioctl(fd, DAHDI_TC_ALLOCATE, &dahdip->fmts)) {
00419 if ((ENODEV == errno) && !tried_once) {
00420
00421
00422
00423
00424
00425
00426
00427
00428 if (AST_FORMAT_SLINEAR == dahdip->fmts.srcfmt) {
00429 ast_debug(1, "Using soft_slin support on source\n");
00430 dahdip->softslin = 1;
00431 dahdip->fmts.srcfmt = AST_FORMAT_ULAW;
00432 } else if (AST_FORMAT_SLINEAR == dahdip->fmts.dstfmt) {
00433 ast_debug(1, "Using soft_slin support on destination\n");
00434 dahdip->softslin = 1;
00435 dahdip->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 dahdip->fd = fd;
00453
00454 dahdip->required_samples = ((dahdip->fmts.dstfmt|dahdip->fmts.srcfmt)&AST_FORMAT_G723_1) ? G723_SAMPLES : G729_SAMPLES;
00455
00456 switch (dahdip->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 ast_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(entry);
00552 ast_unregister_translator(&cur->t);
00553 ast_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 ast_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("/dev/dahdi/transcode", O_RDWR)) < 0) {
00602 ast_log(LOG_ERROR, "Failed to open /dev/dahdi/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 AST_MODULE_LOAD_SUCCESS;
00648 }
00649
00650 static int unload_module(void)
00651 {
00652 ast_cli_unregister_multiple(cli, ARRAY_LEN(cli));
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, ARRAY_LEN(cli));
00663 return AST_MODULE_LOAD_SUCCESS;
00664 }
00665
00666 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Generic DAHDI Transcoder Codec Translator",
00667 .load = load_module,
00668 .unload = unload_module,
00669 .reload = reload,
00670 );