#include "asterisk.h"
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/mman.h>
#include <zaptel/zaptel.h>
#include "asterisk/lock.h"
#include "asterisk/translate.h"
#include "asterisk/config.h"
#include "asterisk/options.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/utils.h"
#include "asterisk/linkedlists.h"
Go to the source code of this file.
Data Structures | |
struct | channel_usage |
struct | format_map |
struct | pvt |
struct | translator |
Defines | |
#define | BUFFER_SAMPLES 8000 |
Functions | |
static | AST_LIST_HEAD_STATIC (translators, translator) |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Generic Zaptel Transcoder Codec Translator",.load=load_module,.unload=unload_module,.reload=reload,) | |
static void | build_translators (struct format_map *map, unsigned int dstfmts, unsigned int srcfmts) |
static void | drop_translator (int dst, int src) |
static struct ast_frame * | fakesrc_sample (void) |
static int | find_transcoders (void) |
static int | load_module (void) |
static void | parse_config (void) |
static int | register_translator (int dst, int src) |
static int | reload (void) |
static int | transcoder_show (int fd, int argc, char **argv) |
static int | unload_module (void) |
static void | unregister_translators (void) |
static void | zap_destroy (struct ast_trans_pvt *pvt) |
static int | zap_framein (struct ast_trans_pvt *pvt, struct ast_frame *f) |
static struct ast_frame * | zap_frameout (struct ast_trans_pvt *pvt) |
static int | zap_new (struct ast_trans_pvt *pvt) |
static int | zap_translate (struct ast_trans_pvt *pvt, int dest, int source) |
Variables | |
static struct channel_usage | channels |
static struct ast_cli_entry | cli [] |
static struct ast_cli_entry | cli_deprecated [] |
static struct format_map | global_format_map = { { { 0 } } } |
static unsigned int | global_useplc = 0 |
static char | show_transcoder_usage [] |
static char | transcoder_show_usage [] |
Definition in file codec_zap.c.
#define BUFFER_SAMPLES 8000 |
Definition at line 60 of file codec_zap.c.
static AST_LIST_HEAD_STATIC | ( | translators | , | |
translator | ||||
) | [static] |
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_DEFAULT | , | |||
"Generic Zaptel Transcoder Codec Translator" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
static void build_translators | ( | struct format_map * | map, | |
unsigned int | dstfmts, | |||
unsigned int | srcfmts | |||
) | [static] |
Definition at line 421 of file codec_zap.c.
References global_format_map, map, format_map::map, and register_translator().
Referenced by find_transcoders().
00422 { 00423 unsigned int src, dst; 00424 00425 for (src = 0; src < 32; src++) { 00426 for (dst = 0; dst < 32; dst++) { 00427 if (!(srcfmts & (1 << src))) 00428 continue; 00429 00430 if (!(dstfmts & (1 << dst))) 00431 continue; 00432 00433 if (global_format_map.map[dst][src]) 00434 continue; 00435 00436 if (!register_translator(dst, src)) 00437 map->map[dst][src] = 1; 00438 } 00439 } 00440 }
static void drop_translator | ( | int | dst, | |
int | src | |||
) | [static] |
Definition at line 367 of file codec_zap.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_unregister_translator(), ast_translator::dstfmt, free, global_format_map, format_map::map, ast_translator::srcfmt, and translator::t.
Referenced by find_transcoders().
00368 { 00369 struct translator *cur; 00370 00371 AST_LIST_LOCK(&translators); 00372 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators, cur, entry) { 00373 if (cur->t.srcfmt != src) 00374 continue; 00375 00376 if (cur->t.dstfmt != dst) 00377 continue; 00378 00379 AST_LIST_REMOVE_CURRENT(&translators, entry); 00380 ast_unregister_translator(&cur->t); 00381 free(cur); 00382 global_format_map.map[dst][src] = 0; 00383 break; 00384 } 00385 AST_LIST_TRAVERSE_SAFE_END; 00386 AST_LIST_UNLOCK(&translators); 00387 }
static struct ast_frame* fakesrc_sample | ( | void | ) | [static] |
Definition at line 321 of file codec_zap.c.
References AST_FRAME_VOICE, and f.
Referenced by register_translator().
00322 { 00323 /* Don't bother really trying to test hardware ones. */ 00324 static struct ast_frame f = { 00325 .frametype = AST_FRAME_VOICE, 00326 .samples = 160, 00327 .src = __PRETTY_FUNCTION__ 00328 }; 00329 00330 return &f; 00331 }
static int find_transcoders | ( | void | ) | [static] |
Definition at line 442 of file codec_zap.c.
References ast_verbose(), build_translators(), channels, drop_translator(), global_format_map, format_map::map, map, option_verbose, channel_usage::total, and VERBOSE_PREFIX_2.
Referenced by load_module().
00443 { 00444 struct zt_transcode_info info = { 0, }; 00445 struct format_map map = { { { 0 } } }; 00446 int fd, res; 00447 unsigned int x, y; 00448 00449 if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) { 00450 ast_verbose(VERBOSE_PREFIX_2 "No hardware transcoders found.\n"); 00451 return 0; 00452 } 00453 00454 info.op = ZT_TCOP_GETINFO; 00455 for (info.tcnum = 0; !(res = ioctl(fd, ZT_TRANSCODE_OP, &info)); info.tcnum++) { 00456 if (option_verbose > 1) 00457 ast_verbose(VERBOSE_PREFIX_2 "Found transcoder '%s'.\n", info.name); 00458 build_translators(&map, info.dstfmts, info.srcfmts); 00459 ast_atomic_fetchadd_int(&channels.total, info.numchannels / 2); 00460 } 00461 00462 close(fd); 00463 00464 if (!info.tcnum && (option_verbose > 1)) 00465 ast_verbose(VERBOSE_PREFIX_2 "No hardware transcoders found.\n"); 00466 00467 for (x = 0; x < 32; x++) { 00468 for (y = 0; y < 32; y++) { 00469 if (!map.map[x][y] && global_format_map.map[x][y]) 00470 drop_translator(x, y); 00471 } 00472 } 00473 00474 return 0; 00475 }
static int load_module | ( | void | ) | [static] |
Definition at line 499 of file codec_zap.c.
References ast_cli_register_multiple(), cli, find_transcoders(), and parse_config().
00500 { 00501 parse_config(); 00502 find_transcoders(); 00503 ast_cli_register_multiple(cli, sizeof(cli) / sizeof(cli[0])); 00504 00505 return 0; 00506 }
static void parse_config | ( | void | ) | [static] |
Definition at line 401 of file codec_zap.c.
References ast_config_load(), ast_true(), ast_variable_browse(), ast_verbose(), option_verbose, var, and VERBOSE_PREFIX_3.
00402 { 00403 struct ast_variable *var; 00404 struct ast_config *cfg = ast_config_load("codecs.conf"); 00405 00406 if (!cfg) 00407 return; 00408 00409 for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) { 00410 if (!strcasecmp(var->name, "genericplc")) { 00411 global_useplc = ast_true(var->value); 00412 if (option_verbose > 2) 00413 ast_verbose(VERBOSE_PREFIX_3 "codec_zap: %susing generic PLC\n", 00414 global_useplc ? "" : "not "); 00415 } 00416 } 00417 00418 ast_config_destroy(cfg); 00419 }
static int register_translator | ( | int | dst, | |
int | src | |||
) | [static] |
Definition at line 333 of file codec_zap.c.
References ast_calloc, ast_getformatname(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_register_translator, BUFFER_SAMPLES, fakesrc_sample(), free, global_format_map, format_map::map, zap_destroy(), zap_framein(), zap_frameout(), and zap_new().
Referenced by build_translators().
00334 { 00335 struct translator *zt; 00336 int res; 00337 00338 if (!(zt = ast_calloc(1, sizeof(*zt)))) 00339 return -1; 00340 00341 snprintf((char *) (zt->t.name), sizeof(zt->t.name), "zap%sto%s", 00342 ast_getformatname((1 << src)), ast_getformatname((1 << dst))); 00343 zt->t.srcfmt = (1 << src); 00344 zt->t.dstfmt = (1 << dst); 00345 zt->t.newpvt = zap_new; 00346 zt->t.framein = zap_framein; 00347 zt->t.frameout = zap_frameout; 00348 zt->t.destroy = zap_destroy; 00349 zt->t.sample = fakesrc_sample; 00350 zt->t.useplc = global_useplc; 00351 zt->t.buf_size = BUFFER_SAMPLES * 2; 00352 zt->t.desc_size = sizeof(struct pvt); 00353 if ((res = ast_register_translator(&zt->t))) { 00354 free(zt); 00355 return -1; 00356 } 00357 00358 AST_LIST_LOCK(&translators); 00359 AST_LIST_INSERT_HEAD(&translators, zt, entry); 00360 AST_LIST_UNLOCK(&translators); 00361 00362 global_format_map.map[dst][src] = 1; 00363 00364 return res; 00365 }
static int reload | ( | void | ) | [static] |
Definition at line 477 of file codec_zap.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, parse_config(), translator::t, and ast_translator::useplc.
00478 { 00479 struct translator *cur; 00480 00481 parse_config(); 00482 00483 AST_LIST_LOCK(&translators); 00484 AST_LIST_TRAVERSE(&translators, cur, entry) 00485 cur->t.useplc = global_useplc; 00486 AST_LIST_UNLOCK(&translators); 00487 00488 return 0; 00489 }
static int transcoder_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 119 of file codec_zap.c.
References ast_cli(), channels, copy(), and RESULT_SUCCESS.
00120 { 00121 struct channel_usage copy; 00122 00123 copy = channels; 00124 00125 if (copy.total == 0) 00126 ast_cli(fd, "No Zaptel transcoders found.\n"); 00127 else 00128 ast_cli(fd, "%d/%d encoders/decoders of %d channels are in use.\n", copy.encoders, copy.decoders, copy.total); 00129 00130 return RESULT_SUCCESS; 00131 }
static int unload_module | ( | void | ) | [static] |
Definition at line 491 of file codec_zap.c.
References ast_cli_unregister_multiple(), cli, and unregister_translators().
00492 { 00493 ast_cli_unregister_multiple(cli, sizeof(cli) / sizeof(cli[0])); 00494 unregister_translators(); 00495 00496 return 0; 00497 }
static void unregister_translators | ( | void | ) | [static] |
Definition at line 389 of file codec_zap.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_unregister_translator(), free, and translator::t.
Referenced by unload_module().
00390 { 00391 struct translator *cur; 00392 00393 AST_LIST_LOCK(&translators); 00394 while ((cur = AST_LIST_REMOVE_HEAD(&translators, entry))) { 00395 ast_unregister_translator(&cur->t); 00396 free(cur); 00397 } 00398 AST_LIST_UNLOCK(&translators); 00399 }
static void zap_destroy | ( | struct ast_trans_pvt * | pvt | ) | [static] |
Definition at line 233 of file codec_zap.c.
References AST_FORMAT_G723_1, AST_FORMAT_G729A, ast_log(), channels, channel_usage::decoders, channel_usage::encoders, errno, pvt::fd, pvt::hdr, LOG_WARNING, and ast_trans_pvt::pvt.
Referenced by register_translator().
00234 { 00235 struct pvt *ztp = pvt->pvt; 00236 unsigned int x; 00237 00238 x = ZT_TCOP_RELEASE; 00239 if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x)) 00240 ast_log(LOG_WARNING, "Failed to release transcoder channel: %s\n", strerror(errno)); 00241 00242 switch (ztp->hdr->dstfmt) { 00243 case AST_FORMAT_G729A: 00244 case AST_FORMAT_G723_1: 00245 ast_atomic_fetchadd_int(&channels.encoders, -1); 00246 break; 00247 default: 00248 ast_atomic_fetchadd_int(&channels.decoders, -1); 00249 break; 00250 } 00251 00252 munmap(ztp->hdr, sizeof(*ztp->hdr)); 00253 close(ztp->fd); 00254 }
static int zap_framein | ( | struct ast_trans_pvt * | pvt, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 133 of file codec_zap.c.
References AST_FORMAT_G729A, ast_log(), f, pvt::fake, pvt::g729b_warning, pvt::hdr, LOG_WARNING, ast_trans_pvt::pvt, and ast_trans_pvt::samples.
Referenced by register_translator().
00134 { 00135 struct pvt *ztp = pvt->pvt; 00136 struct zt_transcode_header *hdr = ztp->hdr; 00137 00138 if (!f->subclass) { 00139 /* Fake a return frame for calculation purposes */ 00140 ztp->fake = 2; 00141 pvt->samples = f->samples; 00142 return 0; 00143 } 00144 00145 if (!hdr->srclen) 00146 /* Copy at front of buffer */ 00147 hdr->srcoffset = 0; 00148 00149 /* if we get handed a G.729 frame that is not a multiple of 00150 10 bytes (10 milliseconds), then it has a CNG frame and 00151 we need to avoid sending that to the transcoder 00152 */ 00153 if ((f->subclass == AST_FORMAT_G729A) && ((f->datalen % 10) != 0)) { 00154 if (!ztp->g729b_warning) { 00155 ast_log(LOG_WARNING, "G.729B CNG frame received but is not supported; dropping.\n"); 00156 ztp->g729b_warning = 1; 00157 } 00158 f->datalen -= f->datalen % 10; 00159 f->samples = f->datalen * 8; 00160 } 00161 00162 if (hdr->srclen + f->datalen > sizeof(hdr->srcdata)) { 00163 ast_log(LOG_WARNING, "Out of space for codec translation!\n"); 00164 return -1; 00165 } 00166 00167 if (hdr->srclen + f->datalen + hdr->srcoffset > sizeof(hdr->srcdata)) { 00168 /* Very unlikely */ 00169 memmove(hdr->srcdata, hdr->srcdata + hdr->srcoffset, hdr->srclen); 00170 hdr->srcoffset = 0; 00171 } 00172 00173 memcpy(hdr->srcdata + hdr->srcoffset + hdr->srclen, f->data, f->datalen); 00174 hdr->srclen += f->datalen; 00175 pvt->samples += f->samples; 00176 00177 return -1; 00178 }
static struct ast_frame* zap_frameout | ( | struct ast_trans_pvt * | pvt | ) | [static] |
Definition at line 180 of file codec_zap.c.
References AST_FRAME_VOICE, AST_FRFLAG_FROM_TRANSLATOR, AST_FRIENDLY_OFFSET, ast_log(), ast_set_flag, ast_frame::data, ast_frame::datalen, errno, ast_trans_pvt::f, pvt::fake, pvt::fd, ast_frame::frametype, pvt::hdr, LOG_WARNING, ast_frame::mallocd, ast_frame::offset, ast_trans_pvt::pvt, ast_trans_pvt::samples, ast_frame::samples, and ast_frame::subclass.
Referenced by register_translator().
00181 { 00182 struct pvt *ztp = pvt->pvt; 00183 struct zt_transcode_header *hdr = ztp->hdr; 00184 unsigned int x; 00185 00186 if (ztp->fake == 2) { 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 } else if (ztp->fake == 1) { 00198 return NULL; 00199 } else { 00200 if (hdr->dstlen) { 00201 #ifdef DEBUG_TRANSCODE 00202 ztp->totalms += hdr->dstsamples; 00203 if ((ztp->totalms - ztp->lasttotalms) > 8000) { 00204 printf("Whee %p, %d (%d to %d)\n", ztp, hdr->dstlen, ztp->lasttotalms, ztp->totalms); 00205 ztp->lasttotalms = ztp->totalms; 00206 } 00207 #endif 00208 pvt->f.frametype = AST_FRAME_VOICE; 00209 pvt->f.subclass = hdr->dstfmt; 00210 pvt->f.samples = hdr->dstsamples; 00211 pvt->f.data = hdr->dstdata + hdr->dstoffset; 00212 pvt->f.offset = hdr->dstoffset; 00213 pvt->f.datalen = hdr->dstlen; 00214 pvt->f.mallocd = 0; 00215 ast_set_flag(&pvt->f, AST_FRFLAG_FROM_TRANSLATOR); 00216 pvt->samples -= pvt->f.samples; 00217 hdr->dstlen = 0; 00218 00219 } else { 00220 if (hdr->srclen) { 00221 hdr->dstoffset = AST_FRIENDLY_OFFSET; 00222 x = ZT_TCOP_TRANSCODE; 00223 if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x)) 00224 ast_log(LOG_WARNING, "Failed to transcode: %s\n", strerror(errno)); 00225 } 00226 return NULL; 00227 } 00228 } 00229 00230 return &pvt->f; 00231 }
static int zap_new | ( | struct ast_trans_pvt * | pvt | ) | [static] |
Definition at line 316 of file codec_zap.c.
References ast_translator::dstfmt, ast_translator::srcfmt, ast_trans_pvt::t, and zap_translate().
Referenced by register_translator().
00317 { 00318 return zap_translate(pvt, pvt->t->dstfmt, pvt->t->srcfmt); 00319 }
static int zap_translate | ( | struct ast_trans_pvt * | pvt, | |
int | dest, | |||
int | source | |||
) | [static] |
Definition at line 256 of file codec_zap.c.
References AST_FORMAT_G723_1, AST_FORMAT_G729A, ast_log(), channels, channel_usage::decoders, channel_usage::encoders, errno, pvt::fd, pvt::hdr, LOG_ERROR, LOG_WARNING, and ast_trans_pvt::pvt.
Referenced by zap_new().
00257 { 00258 /* Request translation through zap if possible */ 00259 int fd; 00260 unsigned int x = ZT_TCOP_ALLOCATE; 00261 struct pvt *ztp = pvt->pvt; 00262 struct zt_transcode_header *hdr; 00263 int flags; 00264 00265 if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) 00266 return -1; 00267 flags = fcntl(fd, F_GETFL); 00268 if (flags > - 1) { 00269 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) 00270 ast_log(LOG_WARNING, "Could not set non-block mode!\n"); 00271 } 00272 00273 00274 if ((hdr = mmap(NULL, sizeof(*hdr), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { 00275 ast_log(LOG_ERROR, "Memory Map failed for transcoding (%s)\n", strerror(errno)); 00276 close(fd); 00277 00278 return -1; 00279 } 00280 00281 if (hdr->magic != ZT_TRANSCODE_MAGIC) { 00282 ast_log(LOG_ERROR, "Transcoder header (%08x) wasn't magic. Abandoning\n", hdr->magic); 00283 munmap(hdr, sizeof(*hdr)); 00284 close(fd); 00285 00286 return -1; 00287 } 00288 00289 hdr->srcfmt = (1 << source); 00290 hdr->dstfmt = (1 << dest); 00291 if (ioctl(fd, ZT_TRANSCODE_OP, &x)) { 00292 ast_log(LOG_ERROR, "Unable to attach transcoder: %s\n", strerror(errno)); 00293 munmap(hdr, sizeof(*hdr)); 00294 close(fd); 00295 00296 return -1; 00297 } 00298 00299 ztp = pvt->pvt; 00300 ztp->fd = fd; 00301 ztp->hdr = hdr; 00302 00303 switch (hdr->dstfmt) { 00304 case AST_FORMAT_G729A: 00305 case AST_FORMAT_G723_1: 00306 ast_atomic_fetchadd_int(&channels.encoders, +1); 00307 break; 00308 default: 00309 ast_atomic_fetchadd_int(&channels.decoders, +1); 00310 break; 00311 } 00312 00313 return 0; 00314 }
struct channel_usage channels [static] |
Referenced by ast_active_channels(), ast_begin_shutdown(), ast_channel_free(), ast_channel_register(), ast_channel_unregister(), ast_get_channel_tech(), ast_request(), channel_find_locked(), check_header(), find_transcoders(), show_channeltype(), show_channeltype_deprecated(), show_channeltypes(), transcoder_show(), zap_destroy(), and zap_translate().
struct ast_cli_entry cli[] [static] |
struct ast_cli_entry cli_deprecated[] [static] |
Definition at line 80 of file codec_zap.c.
struct format_map global_format_map = { { { 0 } } } [static] |
Definition at line 99 of file codec_zap.c.
Referenced by build_translators(), drop_translator(), find_transcoders(), and register_translator().
unsigned int global_useplc = 0 [static] |
Definition at line 62 of file codec_zap.c.
char show_transcoder_usage[] [static] |
Initial value:
"Usage: show transcoder\n" " Displays channel utilization of Zaptel transcoder(s).\n"
Definition at line 70 of file codec_zap.c.
char transcoder_show_usage[] [static] |
Initial value:
"Usage: transcoder show\n" " Displays channel utilization of Zaptel transcoder(s).\n"
Definition at line 74 of file codec_zap.c.