#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 420 of file codec_zap.c.
References format_map::map, and register_translator().
Referenced by find_transcoders().
00421 { 00422 unsigned int src, dst; 00423 00424 for (src = 0; src < 32; src++) { 00425 for (dst = 0; dst < 32; dst++) { 00426 if (!(srcfmts & (1 << src))) 00427 continue; 00428 00429 if (!(dstfmts & (1 << dst))) 00430 continue; 00431 00432 if (global_format_map.map[dst][src]) 00433 continue; 00434 00435 if (!register_translator(dst, src)) 00436 map->map[dst][src] = 1; 00437 } 00438 } 00439 }
static void drop_translator | ( | int | dst, | |
int | src | |||
) | [static] |
Definition at line 366 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, format_map::map, ast_translator::srcfmt, and translator::t.
Referenced by find_transcoders().
00367 { 00368 struct translator *cur; 00369 00370 AST_LIST_LOCK(&translators); 00371 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators, cur, entry) { 00372 if (cur->t.srcfmt != src) 00373 continue; 00374 00375 if (cur->t.dstfmt != dst) 00376 continue; 00377 00378 AST_LIST_REMOVE_CURRENT(&translators, entry); 00379 ast_unregister_translator(&cur->t); 00380 free(cur); 00381 global_format_map.map[dst][src] = 0; 00382 break; 00383 } 00384 AST_LIST_TRAVERSE_SAFE_END; 00385 AST_LIST_UNLOCK(&translators); 00386 }
static struct ast_frame* fakesrc_sample | ( | void | ) | [static, read] |
Definition at line 320 of file codec_zap.c.
References AST_FRAME_VOICE, and ast_frame::frametype.
Referenced by register_translator().
00321 { 00322 /* Don't bother really trying to test hardware ones. */ 00323 static struct ast_frame f = { 00324 .frametype = AST_FRAME_VOICE, 00325 .samples = 160, 00326 .src = __PRETTY_FUNCTION__ 00327 }; 00328 00329 return &f; 00330 }
static int find_transcoders | ( | void | ) | [static] |
Definition at line 441 of file codec_zap.c.
References ast_log(), ast_verbose(), build_translators(), channels, drop_translator(), LOG_DEBUG, format_map::map, option_verbose, channel_usage::total, and VERBOSE_PREFIX_2.
Referenced by load_module().
00442 { 00443 struct zt_transcode_info info = { 0, }; 00444 struct format_map map = { { { 0 } } }; 00445 int fd, res; 00446 unsigned int x, y; 00447 00448 info.op = ZT_TCOP_GETINFO; 00449 if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) { 00450 ast_log(LOG_DEBUG, "No Zaptel transcoder support!\n"); 00451 return 0; 00452 } 00453 for (info.tcnum = 0; !(res = ioctl(fd, ZT_TRANSCODE_OP, &info)); info.tcnum++) { 00454 if (option_verbose > 1) 00455 ast_verbose(VERBOSE_PREFIX_2 "Found transcoder '%s'.\n", info.name); 00456 build_translators(&map, info.dstfmts, info.srcfmts); 00457 ast_atomic_fetchadd_int(&channels.total, info.numchannels / 2); 00458 } 00459 close(fd); 00460 00461 if (!info.tcnum && (option_verbose > 1)) 00462 ast_verbose(VERBOSE_PREFIX_2 "No hardware transcoders found.\n"); 00463 00464 for (x = 0; x < 32; x++) { 00465 for (y = 0; y < 32; y++) { 00466 if (!map.map[x][y] && global_format_map.map[x][y]) 00467 drop_translator(x, y); 00468 } 00469 } 00470 00471 return 0; 00472 }
static int load_module | ( | void | ) | [static] |
Definition at line 496 of file codec_zap.c.
References ast_cli_register_multiple(), find_transcoders(), and parse_config().
00497 { 00498 parse_config(); 00499 find_transcoders(); 00500 ast_cli_register_multiple(cli, sizeof(cli) / sizeof(cli[0])); 00501 00502 return 0; 00503 }
static void parse_config | ( | void | ) | [static] |
Definition at line 400 of file codec_zap.c.
References ast_config_destroy(), ast_config_load(), ast_true(), ast_variable_browse(), ast_verbose(), ast_variable::name, ast_variable::next, option_verbose, ast_variable::value, var, and VERBOSE_PREFIX_3.
00401 { 00402 struct ast_variable *var; 00403 struct ast_config *cfg = ast_config_load("codecs.conf"); 00404 00405 if (!cfg) 00406 return; 00407 00408 for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) { 00409 if (!strcasecmp(var->name, "genericplc")) { 00410 global_useplc = ast_true(var->value); 00411 if (option_verbose > 2) 00412 ast_verbose(VERBOSE_PREFIX_3 "codec_zap: %susing generic PLC\n", 00413 global_useplc ? "" : "not "); 00414 } 00415 } 00416 00417 ast_config_destroy(cfg); 00418 }
static int register_translator | ( | int | dst, | |
int | src | |||
) | [static] |
Definition at line 332 of file codec_zap.c.
References ast_calloc, ast_getformatname(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_register_translator, ast_translator::buf_size, BUFFER_SAMPLES, ast_translator::desc_size, ast_translator::destroy, ast_translator::dstfmt, fakesrc_sample(), ast_translator::framein, ast_translator::frameout, free, format_map::map, ast_translator::name, ast_translator::newpvt, ast_translator::sample, ast_translator::srcfmt, translator::t, ast_translator::useplc, zap_destroy(), zap_framein(), zap_frameout(), and zap_new().
Referenced by build_translators().
00333 { 00334 struct translator *zt; 00335 int res; 00336 00337 if (!(zt = ast_calloc(1, sizeof(*zt)))) 00338 return -1; 00339 00340 snprintf((char *) (zt->t.name), sizeof(zt->t.name), "zap%sto%s", 00341 ast_getformatname((1 << src)), ast_getformatname((1 << dst))); 00342 zt->t.srcfmt = (1 << src); 00343 zt->t.dstfmt = (1 << dst); 00344 zt->t.newpvt = zap_new; 00345 zt->t.framein = zap_framein; 00346 zt->t.frameout = zap_frameout; 00347 zt->t.destroy = zap_destroy; 00348 zt->t.sample = fakesrc_sample; 00349 zt->t.useplc = global_useplc; 00350 zt->t.buf_size = BUFFER_SAMPLES * 2; 00351 zt->t.desc_size = sizeof(struct pvt); 00352 if ((res = ast_register_translator(&zt->t))) { 00353 free(zt); 00354 return -1; 00355 } 00356 00357 AST_LIST_LOCK(&translators); 00358 AST_LIST_INSERT_HEAD(&translators, zt, entry); 00359 AST_LIST_UNLOCK(&translators); 00360 00361 global_format_map.map[dst][src] = 1; 00362 00363 return res; 00364 }
static int reload | ( | void | ) | [static] |
Definition at line 474 of file codec_zap.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, parse_config(), translator::t, and ast_translator::useplc.
00475 { 00476 struct translator *cur; 00477 00478 parse_config(); 00479 00480 AST_LIST_LOCK(&translators); 00481 AST_LIST_TRAVERSE(&translators, cur, entry) 00482 cur->t.useplc = global_useplc; 00483 AST_LIST_UNLOCK(&translators); 00484 00485 return 0; 00486 }
static int transcoder_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 120 of file codec_zap.c.
References ast_cli(), channels, and RESULT_SUCCESS.
00121 { 00122 struct channel_usage copy; 00123 00124 copy = channels; 00125 00126 if (copy.total == 0) 00127 ast_cli(fd, "No Zaptel transcoders found.\n"); 00128 else 00129 ast_cli(fd, "%d/%d encoders/decoders of %d channels are in use.\n", copy.encoders, copy.decoders, copy.total); 00130 00131 return RESULT_SUCCESS; 00132 }
static int unload_module | ( | void | ) | [static] |
Definition at line 488 of file codec_zap.c.
References ast_cli_unregister_multiple(), and unregister_translators().
00489 { 00490 ast_cli_unregister_multiple(cli, sizeof(cli) / sizeof(cli[0])); 00491 unregister_translators(); 00492 00493 return 0; 00494 }
static void unregister_translators | ( | void | ) | [static] |
Definition at line 388 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().
00389 { 00390 struct translator *cur; 00391 00392 AST_LIST_LOCK(&translators); 00393 while ((cur = AST_LIST_REMOVE_HEAD(&translators, entry))) { 00394 ast_unregister_translator(&cur->t); 00395 free(cur); 00396 } 00397 AST_LIST_UNLOCK(&translators); 00398 }
static void zap_destroy | ( | struct ast_trans_pvt * | pvt | ) | [static] |
Definition at line 232 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().
00233 { 00234 struct pvt *ztp = pvt->pvt; 00235 unsigned int x; 00236 00237 x = ZT_TCOP_RELEASE; 00238 if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x)) 00239 ast_log(LOG_WARNING, "Failed to release transcoder channel: %s\n", strerror(errno)); 00240 00241 switch (ztp->hdr->dstfmt) { 00242 case AST_FORMAT_G729A: 00243 case AST_FORMAT_G723_1: 00244 ast_atomic_fetchadd_int(&channels.encoders, -1); 00245 break; 00246 default: 00247 ast_atomic_fetchadd_int(&channels.decoders, -1); 00248 break; 00249 } 00250 00251 munmap(ztp->hdr, sizeof(*ztp->hdr)); 00252 close(ztp->fd); 00253 }
static int zap_framein | ( | struct ast_trans_pvt * | pvt, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 134 of file codec_zap.c.
References AST_FORMAT_G729A, ast_log(), ast_frame::data, ast_frame::datalen, pvt::fake, pvt::g729b_warning, pvt::hdr, LOG_WARNING, ast_trans_pvt::pvt, ast_frame::samples, ast_trans_pvt::samples, and ast_frame::subclass.
Referenced by register_translator().
00135 { 00136 struct pvt *ztp = pvt->pvt; 00137 struct zt_transcode_header *hdr = ztp->hdr; 00138 00139 if (!f->subclass) { 00140 /* Fake a return frame for calculation purposes */ 00141 ztp->fake = 2; 00142 pvt->samples = f->samples; 00143 return 0; 00144 } 00145 00146 if (!hdr->srclen) 00147 /* Copy at front of buffer */ 00148 hdr->srcoffset = 0; 00149 00150 /* if we get handed a G.729 frame that is not a multiple of 00151 10 bytes (10 milliseconds), then it has a CNG frame and 00152 we need to avoid sending that to the transcoder 00153 */ 00154 if ((f->subclass == AST_FORMAT_G729A) && ((f->datalen % 10) != 0)) { 00155 if (!ztp->g729b_warning) { 00156 ast_log(LOG_WARNING, "G.729B CNG frame received but is not supported; dropping.\n"); 00157 ztp->g729b_warning = 1; 00158 } 00159 f->datalen -= f->datalen % 10; 00160 f->samples = f->datalen * 8; 00161 } 00162 00163 if (hdr->srclen + f->datalen > sizeof(hdr->srcdata)) { 00164 ast_log(LOG_WARNING, "Out of space for codec translation!\n"); 00165 return -1; 00166 } 00167 00168 if (hdr->srclen + f->datalen + hdr->srcoffset > sizeof(hdr->srcdata)) { 00169 /* Very unlikely */ 00170 memmove(hdr->srcdata, hdr->srcdata + hdr->srcoffset, hdr->srclen); 00171 hdr->srcoffset = 0; 00172 } 00173 00174 memcpy(hdr->srcdata + hdr->srcoffset + hdr->srclen, f->data, f->datalen); 00175 hdr->srclen += f->datalen; 00176 pvt->samples += f->samples; 00177 00178 return -1; 00179 }
static struct ast_frame* zap_frameout | ( | struct ast_trans_pvt * | pvt | ) | [static, read] |
Definition at line 181 of file codec_zap.c.
References AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_frame::data, ast_frame::datalen, errno, 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().
00182 { 00183 struct pvt *ztp = pvt->pvt; 00184 struct zt_transcode_header *hdr = ztp->hdr; 00185 unsigned int x; 00186 00187 if (ztp->fake == 2) { 00188 ztp->fake = 1; 00189 ztp->f.frametype = AST_FRAME_VOICE; 00190 ztp->f.subclass = 0; 00191 ztp->f.samples = 160; 00192 ztp->f.data = NULL; 00193 ztp->f.offset = 0; 00194 ztp->f.datalen = 0; 00195 ztp->f.mallocd = 0; 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 ztp->f.frametype = AST_FRAME_VOICE; 00209 ztp->f.subclass = hdr->dstfmt; 00210 ztp->f.samples = hdr->dstsamples; 00211 ztp->f.data = hdr->dstdata + hdr->dstoffset; 00212 ztp->f.offset = hdr->dstoffset; 00213 ztp->f.datalen = hdr->dstlen; 00214 ztp->f.mallocd = 0; 00215 pvt->samples -= ztp->f.samples; 00216 hdr->dstlen = 0; 00217 00218 } else { 00219 if (hdr->srclen) { 00220 hdr->dstoffset = AST_FRIENDLY_OFFSET; 00221 x = ZT_TCOP_TRANSCODE; 00222 if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x)) 00223 ast_log(LOG_WARNING, "Failed to transcode: %s\n", strerror(errno)); 00224 } 00225 return NULL; 00226 } 00227 } 00228 00229 return &ztp->f; 00230 }
static int zap_new | ( | struct ast_trans_pvt * | pvt | ) | [static] |
Definition at line 315 of file codec_zap.c.
References ast_translator::dstfmt, ast_translator::srcfmt, ast_trans_pvt::t, and zap_translate().
Referenced by register_translator().
00316 { 00317 return zap_translate(pvt, pvt->t->dstfmt, pvt->t->srcfmt); 00318 }
static int zap_translate | ( | struct ast_trans_pvt * | pvt, | |
int | dest, | |||
int | source | |||
) | [static] |
Definition at line 255 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().
00256 { 00257 /* Request translation through zap if possible */ 00258 int fd; 00259 unsigned int x = ZT_TCOP_ALLOCATE; 00260 struct pvt *ztp = pvt->pvt; 00261 struct zt_transcode_header *hdr; 00262 int flags; 00263 00264 if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) 00265 return -1; 00266 flags = fcntl(fd, F_GETFL); 00267 if (flags > - 1) { 00268 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) 00269 ast_log(LOG_WARNING, "Could not set non-block mode!\n"); 00270 } 00271 00272 00273 if ((hdr = mmap(NULL, sizeof(*hdr), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { 00274 ast_log(LOG_ERROR, "Memory Map failed for transcoding (%s)\n", strerror(errno)); 00275 close(fd); 00276 00277 return -1; 00278 } 00279 00280 if (hdr->magic != ZT_TRANSCODE_MAGIC) { 00281 ast_log(LOG_ERROR, "Transcoder header (%08x) wasn't magic. Abandoning\n", hdr->magic); 00282 munmap(hdr, sizeof(*hdr)); 00283 close(fd); 00284 00285 return -1; 00286 } 00287 00288 hdr->srcfmt = (1 << source); 00289 hdr->dstfmt = (1 << dest); 00290 if (ioctl(fd, ZT_TRANSCODE_OP, &x)) { 00291 ast_log(LOG_ERROR, "Unable to attach transcoder: %s\n", strerror(errno)); 00292 munmap(hdr, sizeof(*hdr)); 00293 close(fd); 00294 00295 return -1; 00296 } 00297 00298 ztp = pvt->pvt; 00299 ztp->fd = fd; 00300 ztp->hdr = hdr; 00301 00302 switch (hdr->dstfmt) { 00303 case AST_FORMAT_G729A: 00304 case AST_FORMAT_G723_1: 00305 ast_atomic_fetchadd_int(&channels.encoders, +1); 00306 break; 00307 default: 00308 ast_atomic_fetchadd_int(&channels.decoders, +1); 00309 break; 00310 } 00311 00312 return 0; 00313 }
struct channel_usage channels [static] |
Referenced by ast_active_channels(), ast_begin_shutdown(), ast_channel_alloc(), ast_channel_free(), ast_channel_register(), ast_channel_unregister(), ast_get_channel_tech(), ast_request_with_uniqueid(), channel_find_locked(), check_header(), find_transcoders(), my_pickup_channel(), show_channeltype(), show_channeltype_deprecated(), show_channeltypes(), transcoder_show(), zap_destroy(), and zap_translate().
struct ast_cli_entry cli[] [static] |
Definition at line 87 of file codec_zap.c.
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.
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.