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: 139151 $")
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
00048 #include "asterisk/lock.h"
00049 #include "asterisk/translate.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/options.h"
00052 #include "asterisk/module.h"
00053 #include "asterisk/cli.h"
00054 #include "asterisk/logger.h"
00055 #include "asterisk/channel.h"
00056 #include "asterisk/utils.h"
00057 #include "asterisk/linkedlists.h"
00058 #include "asterisk/dahdi_compat.h"
00059
00060 #define BUFFER_SAMPLES 8000
00061
00062 static unsigned int global_useplc = 0;
00063
00064 static struct channel_usage {
00065 int total;
00066 int encoders;
00067 int decoders;
00068 } channels;
00069
00070 static char show_transcoder_usage[] =
00071 "Usage: show transcoder\n"
00072 " Displays channel utilization of DAHDI transcoder(s).\n";
00073
00074 static char transcoder_show_usage[] =
00075 "Usage: transcoder show\n"
00076 " Displays channel utilization of DAHDI transcoder(s).\n";
00077
00078 static int transcoder_show(int fd, int argc, char **argv);
00079
00080 static struct ast_cli_entry cli_deprecated[] = {
00081 { { "show", "transcoder", NULL },
00082 transcoder_show,
00083 "Display DAHDI transcoder utilization.",
00084 show_transcoder_usage}
00085 };
00086
00087 static struct ast_cli_entry cli[] = {
00088 { { "transcoder", "show", NULL },
00089 transcoder_show,
00090 "Display DAHDI transcoder utilization.",
00091 transcoder_show_usage, NULL,
00092 &cli_deprecated[0]}
00093 };
00094
00095 struct format_map {
00096 unsigned int map[32][32];
00097 };
00098
00099 static struct format_map global_format_map = { { { 0 } } };
00100
00101 struct translator {
00102 struct ast_translator t;
00103 AST_LIST_ENTRY(translator) entry;
00104 };
00105
00106 static AST_LIST_HEAD_STATIC(translators, translator);
00107
00108 struct pvt {
00109 int fd;
00110 int fake;
00111 int samples;
00112 struct dahdi_transcoder_formats fmts;
00113 };
00114
00115 static int transcoder_show(int fd, int argc, char **argv)
00116 {
00117 struct channel_usage copy;
00118
00119 copy = channels;
00120
00121 if (copy.total == 0)
00122 ast_cli(fd, "No DAHDI transcoders found.\n");
00123 else
00124 ast_cli(fd, "%d/%d encoders/decoders of %d channels are in use.\n", copy.encoders, copy.decoders, copy.total);
00125
00126 return RESULT_SUCCESS;
00127 }
00128
00129 static int zap_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
00130 {
00131 int res;
00132 struct pvt *ztp = pvt->pvt;
00133
00134 if (f->subclass) {
00135
00136 res = write(ztp->fd, f->data, f->datalen);
00137 if (-1 == res) {
00138 ast_log(LOG_ERROR, "Failed to write to transcoder: %s\n", strerror(errno));
00139 }
00140 if (f->datalen != res) {
00141 ast_log(LOG_ERROR, "Requested write of %d bytes, but only wrote %d bytes.\n", f->datalen, res);
00142 }
00143 res = -1;
00144 pvt->samples += f->samples;
00145 } else {
00146
00147 ztp->fake = 2;
00148 pvt->samples = f->samples;
00149 res = 0;
00150 }
00151 return res;
00152 }
00153
00154 static struct ast_frame *zap_frameout(struct ast_trans_pvt *pvt)
00155 {
00156 struct pvt *ztp = pvt->pvt;
00157
00158 if (0 == ztp->fake) {
00159 int res;
00160
00161 res = read(ztp->fd, pvt->outbuf + pvt->datalen, pvt->t->buf_size - pvt->datalen);
00162 if (-1 == res) {
00163 if (EWOULDBLOCK == errno) {
00164
00165 return NULL;
00166 } else {
00167 ast_log(LOG_ERROR, "Failed to read from transcoder: %s\n", strerror(errno));
00168 return NULL;
00169 }
00170 } else {
00171 pvt->f.samples = ztp->samples;
00172 pvt->f.datalen = res;
00173 pvt->datalen = 0;
00174 pvt->f.frametype = AST_FRAME_VOICE;
00175 pvt->f.subclass = 1 << (pvt->t->dstfmt);
00176 pvt->f.mallocd = 0;
00177 pvt->f.offset = AST_FRIENDLY_OFFSET;
00178 pvt->f.src = pvt->t->name;
00179 pvt->f.data = pvt->outbuf;
00180 ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
00181
00182 return &pvt->f;
00183 }
00184
00185 } else if (2 == ztp->fake) {
00186
00187 ztp->fake = 1;
00188 pvt->f.frametype = AST_FRAME_VOICE;
00189 pvt->f.subclass = 0;
00190 pvt->f.samples = 160;
00191 pvt->f.data = NULL;
00192 pvt->f.offset = 0;
00193 pvt->f.datalen = 0;
00194 pvt->f.mallocd = 0;
00195 ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR);
00196 pvt->samples = 0;
00197
00198 return &pvt->f;
00199
00200 } else if (1 == ztp->fake) {
00201
00202 return NULL;
00203
00204 }
00205
00206 return NULL;
00207 }
00208
00209 static void zap_destroy(struct ast_trans_pvt *pvt)
00210 {
00211 struct pvt *ztp = pvt->pvt;
00212
00213 switch (ztp->fmts.dstfmt) {
00214 case AST_FORMAT_G729A:
00215 case AST_FORMAT_G723_1:
00216 ast_atomic_fetchadd_int(&channels.encoders, -1);
00217 break;
00218 default:
00219 ast_atomic_fetchadd_int(&channels.decoders, -1);
00220 break;
00221 }
00222
00223 close(ztp->fd);
00224 }
00225
00226 static int zap_translate(struct ast_trans_pvt *pvt, int dest, int source)
00227 {
00228
00229 int fd;
00230 struct pvt *ztp = pvt->pvt;
00231 int flags;
00232
00233 #ifdef HAVE_ZAPTEL
00234 if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) {
00235 ast_log(LOG_ERROR, "Failed to open /dev/zap/transcode: %s\n", strerror(errno));
00236 return -1;
00237 }
00238 #else
00239 if ((fd = open("/dev/dahdi/transcode", O_RDWR)) < 0) {
00240 ast_log(LOG_ERROR, "Failed to open /dev/dahdi/transcode: %s\n", strerror(errno));
00241 return -1;
00242 }
00243 #endif
00244
00245 ztp->fmts.srcfmt = (1 << source);
00246 ztp->fmts.dstfmt = (1 << dest);
00247
00248 ast_log(LOG_VERBOSE, "Opening transcoder channel from %d to %d.\n", source, dest);
00249
00250 if (ioctl(fd, DAHDI_TC_ALLOCATE, &ztp->fmts)) {
00251 ast_log(LOG_ERROR, "Unable to attach to transcoder: %s\n", strerror(errno));
00252 close(fd);
00253
00254 return -1;
00255 }
00256
00257 flags = fcntl(fd, F_GETFL);
00258 if (flags > - 1) {
00259 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
00260 ast_log(LOG_WARNING, "Could not set non-block mode!\n");
00261 }
00262
00263 ztp->fd = fd;
00264
00265 switch (ztp->fmts.dstfmt) {
00266 case AST_FORMAT_G729A:
00267 ztp->samples = 160;
00268 break;
00269 case AST_FORMAT_G723_1:
00270 ztp->samples = 240;
00271 break;
00272 default:
00273 ztp->samples = 160;
00274 break;
00275 };
00276
00277 switch (ztp->fmts.dstfmt) {
00278 case AST_FORMAT_G729A:
00279 ast_atomic_fetchadd_int(&channels.encoders, +1);
00280 break;
00281 case AST_FORMAT_G723_1:
00282 ast_atomic_fetchadd_int(&channels.encoders, +1);
00283 break;
00284 default:
00285 ast_atomic_fetchadd_int(&channels.decoders, +1);
00286 break;
00287 }
00288
00289 return 0;
00290 }
00291
00292 static int zap_new(struct ast_trans_pvt *pvt)
00293 {
00294 return zap_translate(pvt, pvt->t->dstfmt, pvt->t->srcfmt);
00295 }
00296
00297 static struct ast_frame *fakesrc_sample(void)
00298 {
00299
00300 static struct ast_frame f = {
00301 .frametype = AST_FRAME_VOICE,
00302 .samples = 160,
00303 .src = __PRETTY_FUNCTION__
00304 };
00305
00306 return &f;
00307 }
00308
00309 static int register_translator(int dst, int src)
00310 {
00311 struct translator *zt;
00312 int res;
00313
00314 if (!(zt = ast_calloc(1, sizeof(*zt))))
00315 return -1;
00316
00317 snprintf((char *) (zt->t.name), sizeof(zt->t.name), "zap%sto%s",
00318 ast_getformatname((1 << src)), ast_getformatname((1 << dst)));
00319 zt->t.srcfmt = (1 << src);
00320 zt->t.dstfmt = (1 << dst);
00321 zt->t.newpvt = zap_new;
00322 zt->t.framein = zap_framein;
00323 zt->t.frameout = zap_frameout;
00324 zt->t.destroy = zap_destroy;
00325 zt->t.sample = fakesrc_sample;
00326 zt->t.useplc = global_useplc;
00327 zt->t.buf_size = BUFFER_SAMPLES * 2;
00328 zt->t.desc_size = sizeof(struct pvt);
00329 if ((res = ast_register_translator(&zt->t))) {
00330 free(zt);
00331 return -1;
00332 }
00333
00334 AST_LIST_LOCK(&translators);
00335 AST_LIST_INSERT_HEAD(&translators, zt, entry);
00336 AST_LIST_UNLOCK(&translators);
00337
00338 global_format_map.map[dst][src] = 1;
00339
00340 return res;
00341 }
00342
00343 static void drop_translator(int dst, int src)
00344 {
00345 struct translator *cur;
00346
00347 AST_LIST_LOCK(&translators);
00348 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators, cur, entry) {
00349 if (cur->t.srcfmt != src)
00350 continue;
00351
00352 if (cur->t.dstfmt != dst)
00353 continue;
00354
00355 AST_LIST_REMOVE_CURRENT(&translators, entry);
00356 ast_unregister_translator(&cur->t);
00357 free(cur);
00358 global_format_map.map[dst][src] = 0;
00359 break;
00360 }
00361 AST_LIST_TRAVERSE_SAFE_END;
00362 AST_LIST_UNLOCK(&translators);
00363 }
00364
00365 static void unregister_translators(void)
00366 {
00367 struct translator *cur;
00368
00369 AST_LIST_LOCK(&translators);
00370 while ((cur = AST_LIST_REMOVE_HEAD(&translators, entry))) {
00371 ast_unregister_translator(&cur->t);
00372 free(cur);
00373 }
00374 AST_LIST_UNLOCK(&translators);
00375 }
00376
00377 static void parse_config(void)
00378 {
00379 struct ast_variable *var;
00380 struct ast_config *cfg = ast_config_load("codecs.conf");
00381
00382 if (!cfg)
00383 return;
00384
00385 for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
00386 if (!strcasecmp(var->name, "genericplc")) {
00387 global_useplc = ast_true(var->value);
00388 if (option_verbose > 2)
00389 ast_verbose(VERBOSE_PREFIX_3 "codec_zap: %susing generic PLC\n",
00390 global_useplc ? "" : "not ");
00391 }
00392 }
00393
00394 ast_config_destroy(cfg);
00395 }
00396
00397 static void build_translators(struct format_map *map, unsigned int dstfmts, unsigned int srcfmts)
00398 {
00399 unsigned int src, dst;
00400
00401 for (src = 0; src < 32; src++) {
00402 for (dst = 0; dst < 32; dst++) {
00403 if (!(srcfmts & (1 << src)))
00404 continue;
00405
00406 if (!(dstfmts & (1 << dst)))
00407 continue;
00408
00409 if (global_format_map.map[dst][src])
00410 continue;
00411
00412 if (!register_translator(dst, src))
00413 map->map[dst][src] = 1;
00414 }
00415 }
00416 }
00417
00418 static int find_transcoders(void)
00419 {
00420 struct dahdi_transcoder_info info = { 0, };
00421 struct format_map map = { { { 0 } } };
00422 int fd, res;
00423 unsigned int x, y;
00424
00425 #ifdef HAVE_ZAPTEL
00426 if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) {
00427 ast_log(LOG_ERROR, "Failed to open /dev/zap/transcode: %s\n", strerror(errno));
00428 return 0;
00429 }
00430 #else
00431 if ((fd = open("/dev/dahdi/transcode", O_RDWR)) < 0) {
00432 ast_log(LOG_ERROR, "Failed to open /dev/dahdi/transcode: %s\n", strerror(errno));
00433 return 0;
00434 }
00435 #endif
00436
00437 for (info.tcnum = 0; !(res = ioctl(fd, DAHDI_TC_GETINFO, &info)); info.tcnum++) {
00438 if (option_verbose > 1)
00439 ast_verbose(VERBOSE_PREFIX_2 "Found transcoder '%s'.\n", info.name);
00440 build_translators(&map, info.dstfmts, info.srcfmts);
00441 ast_atomic_fetchadd_int(&channels.total, info.numchannels / 2);
00442 }
00443
00444 close(fd);
00445
00446 if (!info.tcnum && (option_verbose > 1))
00447 ast_verbose(VERBOSE_PREFIX_2 "No hardware transcoders found.\n");
00448
00449 for (x = 0; x < 32; x++) {
00450 for (y = 0; y < 32; y++) {
00451 if (!map.map[x][y] && global_format_map.map[x][y])
00452 drop_translator(x, y);
00453 }
00454 }
00455
00456 return 0;
00457 }
00458
00459 static int reload(void)
00460 {
00461 struct translator *cur;
00462
00463 parse_config();
00464
00465 AST_LIST_LOCK(&translators);
00466 AST_LIST_TRAVERSE(&translators, cur, entry)
00467 cur->t.useplc = global_useplc;
00468 AST_LIST_UNLOCK(&translators);
00469
00470 return 0;
00471 }
00472
00473 static int unload_module(void)
00474 {
00475 ast_cli_unregister_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00476 unregister_translators();
00477
00478 return 0;
00479 }
00480
00481 static int load_module(void)
00482 {
00483 parse_config();
00484 find_transcoders();
00485 ast_cli_register_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00486
00487 return 0;
00488 }
00489
00490 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Generic DAHDI Transcoder Codec Translator",
00491 .load = load_module,
00492 .unload = unload_module,
00493 .reload = reload,
00494 );