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: 165991 $")
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 if ((fd = open(DAHDI_FILE_TRANSCODE, O_RDWR)) < 0) {
00234 ast_log(LOG_ERROR, "Failed to open " DAHDI_FILE_TRANSCODE ": %s\n", strerror(errno));
00235 return -1;
00236 }
00237
00238 ztp->fmts.srcfmt = (1 << source);
00239 ztp->fmts.dstfmt = (1 << dest);
00240
00241 ast_log(LOG_VERBOSE, "Opening transcoder channel from %d to %d.\n", source, dest);
00242
00243 if (ioctl(fd, DAHDI_TC_ALLOCATE, &ztp->fmts)) {
00244 ast_log(LOG_ERROR, "Unable to attach to transcoder: %s\n", strerror(errno));
00245 close(fd);
00246
00247 return -1;
00248 }
00249
00250 flags = fcntl(fd, F_GETFL);
00251 if (flags > - 1) {
00252 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
00253 ast_log(LOG_WARNING, "Could not set non-block mode!\n");
00254 }
00255
00256 ztp->fd = fd;
00257
00258 switch (ztp->fmts.dstfmt) {
00259 case AST_FORMAT_G729A:
00260 ztp->samples = 160;
00261 break;
00262 case AST_FORMAT_G723_1:
00263 ztp->samples = 240;
00264 break;
00265 default:
00266 ztp->samples = 160;
00267 break;
00268 };
00269
00270 switch (ztp->fmts.dstfmt) {
00271 case AST_FORMAT_G729A:
00272 ast_atomic_fetchadd_int(&channels.encoders, +1);
00273 break;
00274 case AST_FORMAT_G723_1:
00275 ast_atomic_fetchadd_int(&channels.encoders, +1);
00276 break;
00277 default:
00278 ast_atomic_fetchadd_int(&channels.decoders, +1);
00279 break;
00280 }
00281
00282 return 0;
00283 }
00284
00285 static int zap_new(struct ast_trans_pvt *pvt)
00286 {
00287 return zap_translate(pvt, pvt->t->dstfmt, pvt->t->srcfmt);
00288 }
00289
00290 static struct ast_frame *fakesrc_sample(void)
00291 {
00292
00293 static struct ast_frame f = {
00294 .frametype = AST_FRAME_VOICE,
00295 .samples = 160,
00296 .src = __PRETTY_FUNCTION__
00297 };
00298
00299 return &f;
00300 }
00301
00302 static int register_translator(int dst, int src)
00303 {
00304 struct translator *zt;
00305 int res;
00306
00307 if (!(zt = ast_calloc(1, sizeof(*zt))))
00308 return -1;
00309
00310 snprintf((char *) (zt->t.name), sizeof(zt->t.name), "zap%sto%s",
00311 ast_getformatname((1 << src)), ast_getformatname((1 << dst)));
00312 zt->t.srcfmt = (1 << src);
00313 zt->t.dstfmt = (1 << dst);
00314 zt->t.newpvt = zap_new;
00315 zt->t.framein = zap_framein;
00316 zt->t.frameout = zap_frameout;
00317 zt->t.destroy = zap_destroy;
00318 zt->t.sample = fakesrc_sample;
00319 zt->t.useplc = global_useplc;
00320 zt->t.buf_size = BUFFER_SAMPLES * 2;
00321 zt->t.desc_size = sizeof(struct pvt);
00322 if ((res = ast_register_translator(&zt->t))) {
00323 free(zt);
00324 return -1;
00325 }
00326
00327 AST_LIST_LOCK(&translators);
00328 AST_LIST_INSERT_HEAD(&translators, zt, entry);
00329 AST_LIST_UNLOCK(&translators);
00330
00331 global_format_map.map[dst][src] = 1;
00332
00333 return res;
00334 }
00335
00336 static void drop_translator(int dst, int src)
00337 {
00338 struct translator *cur;
00339
00340 AST_LIST_LOCK(&translators);
00341 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators, cur, entry) {
00342 if (cur->t.srcfmt != src)
00343 continue;
00344
00345 if (cur->t.dstfmt != dst)
00346 continue;
00347
00348 AST_LIST_REMOVE_CURRENT(&translators, entry);
00349 ast_unregister_translator(&cur->t);
00350 free(cur);
00351 global_format_map.map[dst][src] = 0;
00352 break;
00353 }
00354 AST_LIST_TRAVERSE_SAFE_END;
00355 AST_LIST_UNLOCK(&translators);
00356 }
00357
00358 static void unregister_translators(void)
00359 {
00360 struct translator *cur;
00361
00362 AST_LIST_LOCK(&translators);
00363 while ((cur = AST_LIST_REMOVE_HEAD(&translators, entry))) {
00364 ast_unregister_translator(&cur->t);
00365 free(cur);
00366 }
00367 AST_LIST_UNLOCK(&translators);
00368 }
00369
00370 static void parse_config(void)
00371 {
00372 struct ast_variable *var;
00373 struct ast_config *cfg = ast_config_load("codecs.conf");
00374
00375 if (!cfg)
00376 return;
00377
00378 for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
00379 if (!strcasecmp(var->name, "genericplc")) {
00380 global_useplc = ast_true(var->value);
00381 if (option_verbose > 2)
00382 ast_verbose(VERBOSE_PREFIX_3 "codec_zap: %susing generic PLC\n",
00383 global_useplc ? "" : "not ");
00384 }
00385 }
00386
00387 ast_config_destroy(cfg);
00388 }
00389
00390 static void build_translators(struct format_map *map, unsigned int dstfmts, unsigned int srcfmts)
00391 {
00392 unsigned int src, dst;
00393
00394 for (src = 0; src < 32; src++) {
00395 for (dst = 0; dst < 32; dst++) {
00396 if (!(srcfmts & (1 << src)))
00397 continue;
00398
00399 if (!(dstfmts & (1 << dst)))
00400 continue;
00401
00402 if (global_format_map.map[dst][src])
00403 continue;
00404
00405 if (!register_translator(dst, src))
00406 map->map[dst][src] = 1;
00407 }
00408 }
00409 }
00410
00411 static int find_transcoders(void)
00412 {
00413 struct dahdi_transcoder_info info = { 0, };
00414 struct format_map map = { { { 0 } } };
00415 int fd, res;
00416 unsigned int x, y;
00417
00418 if ((fd = open(DAHDI_FILE_TRANSCODE, O_RDWR)) < 0) {
00419 ast_log(LOG_ERROR, "Failed to open " DAHDI_FILE_TRANSCODE ": %s\n", strerror(errno));
00420 return 0;
00421 }
00422
00423 for (info.tcnum = 0; !(res = ioctl(fd, DAHDI_TC_GETINFO, &info)); info.tcnum++) {
00424 if (option_verbose > 1)
00425 ast_verbose(VERBOSE_PREFIX_2 "Found transcoder '%s'.\n", info.name);
00426 build_translators(&map, info.dstfmts, info.srcfmts);
00427 ast_atomic_fetchadd_int(&channels.total, info.numchannels / 2);
00428 }
00429
00430 close(fd);
00431
00432 if (!info.tcnum && (option_verbose > 1))
00433 ast_verbose(VERBOSE_PREFIX_2 "No hardware transcoders found.\n");
00434
00435 for (x = 0; x < 32; x++) {
00436 for (y = 0; y < 32; y++) {
00437 if (!map.map[x][y] && global_format_map.map[x][y])
00438 drop_translator(x, y);
00439 }
00440 }
00441
00442 return 0;
00443 }
00444
00445 static int reload(void)
00446 {
00447 struct translator *cur;
00448
00449 parse_config();
00450
00451 AST_LIST_LOCK(&translators);
00452 AST_LIST_TRAVERSE(&translators, cur, entry)
00453 cur->t.useplc = global_useplc;
00454 AST_LIST_UNLOCK(&translators);
00455
00456 return 0;
00457 }
00458
00459 static int unload_module(void)
00460 {
00461 ast_cli_unregister_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00462 unregister_translators();
00463
00464 return 0;
00465 }
00466
00467 static int load_module(void)
00468 {
00469 parse_config();
00470 find_transcoders();
00471 ast_cli_register_multiple(cli, sizeof(cli) / sizeof(cli[0]));
00472
00473 return 0;
00474 }
00475
00476 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Generic DAHDI Transcoder Codec Translator",
00477 .load = load_module,
00478 .unload = unload_module,
00479 .reload = reload,
00480 );