#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/chanspy.h"
#include "asterisk/features.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/say.h"
#include "asterisk/pbx.h"
#include "asterisk/translate.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
Include dependency graph for app_chanspy.c:
Go to the source code of this file.
Data Structures | |
struct | chanspy_translation_helper |
Defines | |
#define | AST_NAME_STRLEN 256 |
Enumerations | |
enum | { OPTION_QUIET = (1 << 0), OPTION_BRIDGED = (1 << 1), OPTION_VOLUME = (1 << 2), OPTION_GROUP = (1 << 3), OPTION_RECORD = (1 << 4), OPTION_WHISPER = (1 << 5), OPTION_PRIVATE = (1 << 6) } |
enum | { OPT_ARG_VOLUME = 0, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_ARRAY_SIZE } |
Functions | |
AST_APP_OPTIONS (spy_opts,{AST_APP_OPTION('q', OPTION_QUIET), AST_APP_OPTION('b', OPTION_BRIDGED), AST_APP_OPTION('w', OPTION_WHISPER), AST_APP_OPTION('W', OPTION_PRIVATE), AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME), AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP), AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),}) | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Listen to the audio of an active channel") | |
static int | channel_spy (struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd, const struct ast_flags *flags) |
static int | chanspy_exec (struct ast_channel *chan, void *data) |
static int | common_exec (struct ast_channel *chan, const struct ast_flags *flags, int volfactor, const int fd, const char *mygroup, const char *spec, const char *exten, const char *context) |
static int | extenspy_exec (struct ast_channel *chan, void *data) |
static int | load_module (void) |
static struct ast_channel * | next_channel (const struct ast_channel *last, const char *spec, const char *exten, const char *context) |
static void | set_volume (struct ast_channel *chan, struct chanspy_translation_helper *csth) |
static void * | spy_alloc (struct ast_channel *chan, void *data) |
static int | spy_generate (struct ast_channel *chan, void *data, int len, int samples) |
static void | spy_release (struct ast_channel *chan, void *data) |
static int | start_spying (struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy) |
static int | unload_module (void) |
Variables | |
static const char * | app_chan = "ChanSpy" |
static const char * | app_ext = "ExtenSpy" |
enum { ... } | chanspy_opt_args |
enum { ... } | chanspy_opt_flags |
static const char * | desc_chan |
static const char * | desc_ext |
static struct ast_generator | spygen |
static const char * | tdesc = "Listen to a channel, and optionally whisper into it" |
static signed char | volfactor_map [] |
Definition in file app_chanspy.c.
#define AST_NAME_STRLEN 256 |
anonymous enum |
OPTION_QUIET | |
OPTION_BRIDGED | |
OPTION_VOLUME | |
OPTION_GROUP | |
OPTION_RECORD | |
OPTION_WHISPER | |
OPTION_PRIVATE |
Definition at line 116 of file app_chanspy.c.
00116 { 00117 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */ 00118 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */ 00119 OPTION_VOLUME = (1 << 2), /* Specify initial volume */ 00120 OPTION_GROUP = (1 << 3), /* Only look at channels in group */ 00121 OPTION_RECORD = (1 << 4), 00122 OPTION_WHISPER = (1 << 5), 00123 OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */ 00124 } chanspy_opt_flags;
anonymous enum |
Definition at line 126 of file app_chanspy.c.
00126 { 00127 OPT_ARG_VOLUME = 0, 00128 OPT_ARG_GROUP, 00129 OPT_ARG_RECORD, 00130 OPT_ARG_ARRAY_SIZE, 00131 } chanspy_opt_args;
AST_APP_OPTIONS | ( | spy_opts | ) |
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Listen to the audio of an active channel" | ||||
) |
static int channel_spy | ( | struct ast_channel * | chan, | |
struct ast_channel * | spyee, | |||
int * | volfactor, | |||
int | fd, | |||
const struct ast_flags * | flags | |||
) | [static] |
Definition at line 243 of file app_chanspy.c.
References ast_activate_generator(), ast_channel_lock, ast_channel_spy_free(), ast_channel_spy_remove(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unlock, ast_channel_whisper_feed(), ast_channel_whisper_start(), ast_channel_whisper_stop(), ast_check_hangup(), ast_clear_flag, ast_closestream(), ast_deactivate_generator(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree(), ast_mutex_destroy(), ast_mutex_init(), ast_openstream_full(), ast_read(), ast_readframe(), ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_waitfor(), CHANSPY_DONE, CHANSPY_FORMAT_AUDIO, CHANSPY_MIXAUDIO, CHANSPY_READ_VOLADJUST, CHANSPY_RUNNING, CHANSPY_TRIGGER_NONE, CHANSPY_WRITE_VOLADJUST, f, name, OPTION_PRIVATE, option_verbose, OPTION_WHISPER, set_volume(), spygen, start_spying(), ast_channel::stream, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and ast_channel::writeformat.
Referenced by common_exec().
00245 { 00246 struct chanspy_translation_helper csth; 00247 int running = 0, res, x = 0; 00248 char inp[24] = {0}; 00249 char *name; 00250 struct ast_frame *f; 00251 struct ast_silence_generator *silgen = NULL; 00252 00253 if (ast_check_hangup(chan) || ast_check_hangup(spyee)) 00254 return 0; 00255 00256 name = ast_strdupa(spyee->name); 00257 if (option_verbose >= 2) 00258 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name); 00259 00260 memset(&csth, 0, sizeof(csth)); 00261 ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO); 00262 ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE); 00263 ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO); 00264 csth.spy.type = "ChanSpy"; 00265 csth.spy.status = CHANSPY_RUNNING; 00266 csth.spy.read_queue.format = AST_FORMAT_SLINEAR; 00267 csth.spy.write_queue.format = AST_FORMAT_SLINEAR; 00268 ast_mutex_init(&csth.spy.lock); 00269 csth.volfactor = *volfactor; 00270 set_volume(chan, &csth); 00271 if (csth.volfactor) { 00272 ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST); 00273 csth.spy.read_vol_adjustment = csth.volfactor; 00274 ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST); 00275 csth.spy.write_vol_adjustment = csth.volfactor; 00276 } 00277 csth.fd = fd; 00278 00279 if (start_spying(spyee, chan, &csth.spy)) { 00280 ast_mutex_destroy(&csth.spy.lock); 00281 return 0; 00282 } 00283 00284 if (ast_test_flag(flags, OPTION_WHISPER)) { 00285 struct ast_filestream *beepstream; 00286 int old_write_format = 0; 00287 00288 ast_channel_whisper_start(csth.spy.chan); 00289 old_write_format = chan->writeformat; 00290 if ((beepstream = ast_openstream_full(chan, "beep", chan->language, 1))) { 00291 struct ast_frame *f; 00292 00293 while ((f = ast_readframe(beepstream))) { 00294 ast_channel_whisper_feed(csth.spy.chan, f); 00295 ast_frfree(f); 00296 } 00297 00298 ast_closestream(beepstream); 00299 chan->stream = NULL; 00300 } 00301 if (old_write_format) 00302 ast_set_write_format(chan, old_write_format); 00303 } 00304 00305 if (ast_test_flag(flags, OPTION_PRIVATE)) 00306 silgen = ast_channel_start_silence_generator(chan); 00307 else 00308 ast_activate_generator(chan, &spygen, &csth); 00309 00310 /* We can no longer rely on 'spyee' being an actual channel; 00311 it can be hung up and freed out from under us. However, the 00312 channel destructor will put NULL into our csth.spy.chan 00313 field when that happens, so that is our signal that the spyee 00314 channel has gone away. 00315 */ 00316 00317 /* Note: it is very important that the ast_waitfor() be the first 00318 condition in this expression, so that if we wait for some period 00319 of time before receiving a frame from our spying channel, we check 00320 for hangup on the spied-on channel _after_ knowing that a frame 00321 has arrived, since the spied-on channel could have gone away while 00322 we were waiting 00323 */ 00324 while ((res = ast_waitfor(chan, -1) > -1) && 00325 csth.spy.status == CHANSPY_RUNNING && 00326 csth.spy.chan) { 00327 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) { 00328 running = -1; 00329 break; 00330 } 00331 00332 if (ast_test_flag(flags, OPTION_WHISPER) && 00333 (f->frametype == AST_FRAME_VOICE)) { 00334 ast_channel_whisper_feed(csth.spy.chan, f); 00335 ast_frfree(f); 00336 continue; 00337 } 00338 00339 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0; 00340 ast_frfree(f); 00341 if (!res) 00342 continue; 00343 00344 if (x == sizeof(inp)) 00345 x = 0; 00346 00347 if (res < 0) { 00348 running = -1; 00349 break; 00350 } 00351 00352 if (res == '*') { 00353 running = 0; 00354 break; 00355 } else if (res == '#') { 00356 if (!ast_strlen_zero(inp)) { 00357 running = atoi(inp); 00358 break; 00359 } 00360 00361 (*volfactor)++; 00362 if (*volfactor > 4) 00363 *volfactor = -4; 00364 if (option_verbose > 2) 00365 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor); 00366 csth.volfactor = *volfactor; 00367 set_volume(chan, &csth); 00368 if (csth.volfactor) { 00369 ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST); 00370 csth.spy.read_vol_adjustment = csth.volfactor; 00371 ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST); 00372 csth.spy.write_vol_adjustment = csth.volfactor; 00373 } else { 00374 ast_clear_flag(&csth.spy, CHANSPY_READ_VOLADJUST); 00375 ast_clear_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST); 00376 } 00377 } else if (res >= '0' && res <= '9') { 00378 inp[x++] = res; 00379 } 00380 } 00381 00382 if (ast_test_flag(flags, OPTION_WHISPER) && csth.spy.chan) 00383 ast_channel_whisper_stop(csth.spy.chan); 00384 00385 if (ast_test_flag(flags, OPTION_PRIVATE)) 00386 ast_channel_stop_silence_generator(chan, silgen); 00387 else 00388 ast_deactivate_generator(chan); 00389 00390 csth.spy.status = CHANSPY_DONE; 00391 00392 /* If a channel still exists on our spy structure then we need to remove ourselves */ 00393 if (csth.spy.chan) { 00394 ast_channel_lock(csth.spy.chan); 00395 ast_channel_spy_remove(csth.spy.chan, &csth.spy); 00396 ast_channel_unlock(csth.spy.chan); 00397 } 00398 ast_channel_spy_free(&csth.spy); 00399 00400 if (option_verbose >= 2) 00401 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name); 00402 00403 return running; 00404 }
static int chanspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 558 of file app_chanspy.c.
References ast_app_parse_options(), ast_app_separate_args(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_module_user_add, ast_module_user_remove, ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), ast_test_flag, common_exec(), ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_GROUP, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, and ast_channel::writeformat.
Referenced by load_module().
00559 { 00560 struct ast_module_user *u; 00561 char *options = NULL; 00562 char *spec = NULL; 00563 char *argv[2]; 00564 char *mygroup = NULL; 00565 char *recbase = NULL; 00566 int fd = 0; 00567 struct ast_flags flags; 00568 int oldwf = 0; 00569 int argc = 0; 00570 int volfactor = 0; 00571 int res; 00572 00573 data = ast_strdupa(data); 00574 00575 u = ast_module_user_add(chan); 00576 00577 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00578 spec = argv[0]; 00579 if (argc > 1) 00580 options = argv[1]; 00581 00582 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) 00583 spec = NULL; 00584 } 00585 00586 if (options) { 00587 char *opts[OPT_ARG_ARRAY_SIZE]; 00588 00589 ast_app_parse_options(spy_opts, &flags, opts, options); 00590 if (ast_test_flag(&flags, OPTION_GROUP)) 00591 mygroup = opts[OPT_ARG_GROUP]; 00592 00593 if (ast_test_flag(&flags, OPTION_RECORD) && 00594 !(recbase = opts[OPT_ARG_RECORD])) 00595 recbase = "chanspy"; 00596 00597 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00598 int vol; 00599 00600 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00601 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00602 else 00603 volfactor = vol; 00604 } 00605 00606 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00607 ast_set_flag(&flags, OPTION_WHISPER); 00608 } else 00609 ast_clear_flag(&flags, AST_FLAGS_ALL); 00610 00611 oldwf = chan->writeformat; 00612 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00613 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00614 ast_module_user_remove(u); 00615 return -1; 00616 } 00617 00618 if (recbase) { 00619 char filename[512]; 00620 00621 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00622 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00623 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00624 fd = 0; 00625 } 00626 } 00627 00628 res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL); 00629 00630 if (fd) 00631 close(fd); 00632 00633 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00634 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00635 00636 ast_module_user_remove(u); 00637 00638 return res; 00639 }
static int common_exec | ( | struct ast_channel * | chan, | |
const struct ast_flags * | flags, | |||
int | volfactor, | |||
const int | fd, | |||
const char * | mygroup, | |||
const char * | spec, | |||
const char * | exten, | |||
const char * | context | |||
) | [static] |
Definition at line 428 of file app_chanspy.c.
References ast_channel::_state, ast_answer(), ast_app_separate_args(), ast_bridged_channel(), ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, ast_fileexists(), AST_FLAG_SPYING, ast_get_channel_by_name_prefix_locked(), AST_NAME_STRLEN, AST_OPTION_TXGAIN, ast_say_character_str(), ast_say_digits(), ast_set_flag, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_test_flag, ast_waitfordigit(), ast_waitstream(), channel_spy(), ast_channel::flags, group, next_channel(), OPTION_BRIDGED, OPTION_QUIET, pbx_builtin_getvar_helper(), and s.
Referenced by chanspy_exec(), and extenspy_exec().
00431 { 00432 struct ast_channel *peer, *prev, *next; 00433 char nameprefix[AST_NAME_STRLEN]; 00434 char peer_name[AST_NAME_STRLEN + 5]; 00435 signed char zero_volume = 0; 00436 int waitms; 00437 int res; 00438 char *ptr; 00439 int num; 00440 00441 if (chan->_state != AST_STATE_UP) 00442 ast_answer(chan); 00443 00444 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ 00445 00446 waitms = 100; 00447 00448 for (;;) { 00449 if (!ast_test_flag(flags, OPTION_QUIET)) { 00450 res = ast_streamfile(chan, "beep", chan->language); 00451 if (!res) 00452 res = ast_waitstream(chan, ""); 00453 else if (res < 0) { 00454 ast_clear_flag(chan, AST_FLAG_SPYING); 00455 break; 00456 } 00457 } 00458 00459 res = ast_waitfordigit(chan, waitms); 00460 if (res < 0) { 00461 ast_clear_flag(chan, AST_FLAG_SPYING); 00462 break; 00463 } 00464 00465 /* reset for the next loop around, unless overridden later */ 00466 waitms = 100; 00467 peer = prev = next = NULL; 00468 00469 for (peer = next_channel(peer, spec, exten, context); 00470 peer; 00471 prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) { 00472 const char *group; 00473 int igrp = !mygroup; 00474 char *groups[25]; 00475 int num_groups = 0; 00476 char *dup_group; 00477 int x; 00478 char *s; 00479 00480 if (peer == prev) 00481 break; 00482 00483 if (peer == chan) 00484 continue; 00485 00486 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) 00487 continue; 00488 00489 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) 00490 continue; 00491 00492 if (mygroup) { 00493 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { 00494 dup_group = ast_strdupa(group); 00495 num_groups = ast_app_separate_args(dup_group, ':', groups, 00496 sizeof(groups) / sizeof(groups[0])); 00497 } 00498 00499 for (x = 0; x < num_groups; x++) { 00500 if (!strcmp(mygroup, groups[x])) { 00501 igrp = 1; 00502 break; 00503 } 00504 } 00505 } 00506 00507 if (!igrp) 00508 continue; 00509 00510 strcpy(peer_name, "spy-"); 00511 strncat(peer_name, peer->name, AST_NAME_STRLEN); 00512 ptr = strchr(peer_name, '/'); 00513 *ptr++ = '\0'; 00514 00515 for (s = peer_name; s < ptr; s++) 00516 *s = tolower(*s); 00517 00518 if (!ast_test_flag(flags, OPTION_QUIET)) { 00519 if (ast_fileexists(peer_name, NULL, NULL) != -1) { 00520 res = ast_streamfile(chan, peer_name, chan->language); 00521 if (!res) 00522 res = ast_waitstream(chan, ""); 00523 if (res) 00524 break; 00525 } else 00526 res = ast_say_character_str(chan, peer_name, "", chan->language); 00527 if ((num = atoi(ptr))) 00528 ast_say_digits(chan, atoi(ptr), "", chan->language); 00529 } 00530 00531 waitms = 5000; 00532 res = channel_spy(chan, peer, &volfactor, fd, flags); 00533 00534 if (res == -1) { 00535 break; 00536 } else if (res > 1 && spec) { 00537 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); 00538 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { 00539 ast_channel_unlock(next); 00540 } else { 00541 /* stay on this channel */ 00542 next = peer; 00543 } 00544 peer = NULL; 00545 } 00546 } 00547 if (res == -1) 00548 break; 00549 } 00550 00551 ast_clear_flag(chan, AST_FLAG_SPYING); 00552 00553 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 00554 00555 return res; 00556 }
static int extenspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 641 of file app_chanspy.c.
References ast_app_parse_options(), ast_app_separate_args(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_module_user_add, ast_module_user_remove, ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), ast_test_flag, common_exec(), ast_channel::context, context, exten, ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_GROUP, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, strsep(), and ast_channel::writeformat.
Referenced by load_module().
00642 { 00643 struct ast_module_user *u; 00644 char *options = NULL; 00645 char *exten = NULL; 00646 char *context = NULL; 00647 char *argv[2]; 00648 char *mygroup = NULL; 00649 char *recbase = NULL; 00650 int fd = 0; 00651 struct ast_flags flags; 00652 int oldwf = 0; 00653 int argc = 0; 00654 int volfactor = 0; 00655 int res; 00656 00657 data = ast_strdupa(data); 00658 00659 u = ast_module_user_add(chan); 00660 00661 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00662 context = argv[0]; 00663 if (!ast_strlen_zero(argv[0])) 00664 exten = strsep(&context, "@"); 00665 if (ast_strlen_zero(context)) 00666 context = ast_strdupa(chan->context); 00667 if (argc > 1) 00668 options = argv[1]; 00669 } 00670 00671 if (options) { 00672 char *opts[OPT_ARG_ARRAY_SIZE]; 00673 00674 ast_app_parse_options(spy_opts, &flags, opts, options); 00675 if (ast_test_flag(&flags, OPTION_GROUP)) 00676 mygroup = opts[OPT_ARG_GROUP]; 00677 00678 if (ast_test_flag(&flags, OPTION_RECORD) && 00679 !(recbase = opts[OPT_ARG_RECORD])) 00680 recbase = "chanspy"; 00681 00682 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00683 int vol; 00684 00685 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00686 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00687 else 00688 volfactor = vol; 00689 } 00690 00691 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00692 ast_set_flag(&flags, OPTION_WHISPER); 00693 } else 00694 ast_clear_flag(&flags, AST_FLAGS_ALL); 00695 00696 oldwf = chan->writeformat; 00697 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00698 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00699 ast_module_user_remove(u); 00700 return -1; 00701 } 00702 00703 if (recbase) { 00704 char filename[512]; 00705 00706 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00707 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00708 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00709 fd = 0; 00710 } 00711 } 00712 00713 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context); 00714 00715 if (fd) 00716 close(fd); 00717 00718 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00719 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00720 00721 ast_module_user_remove(u); 00722 00723 return res; 00724 }
static int load_module | ( | void | ) | [static] |
Definition at line 738 of file app_chanspy.c.
References ast_register_application(), chanspy_exec(), and extenspy_exec().
00739 { 00740 int res = 0; 00741 00742 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan); 00743 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext); 00744 00745 return res; 00746 }
static struct ast_channel* next_channel | ( | const struct ast_channel * | last, | |
const char * | spec, | |||
const char * | exten, | |||
const char * | context | |||
) | [static] |
Definition at line 406 of file app_chanspy.c.
References ast_channel_unlock, ast_channel_walk_locked(), ast_walk_channel_by_exten_locked(), ast_walk_channel_by_name_prefix_locked(), and last.
Referenced by common_exec().
00408 { 00409 struct ast_channel *this; 00410 00411 redo: 00412 if (spec) 00413 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec)); 00414 else if (exten) 00415 this = ast_walk_channel_by_exten_locked(last, exten, context); 00416 else 00417 this = ast_channel_walk_locked(last); 00418 00419 if (this) { 00420 ast_channel_unlock(this); 00421 if (!strncmp(this->name, "Zap/pseudo", 10)) 00422 goto redo; 00423 } 00424 00425 return this; 00426 }
static void set_volume | ( | struct ast_channel * | chan, | |
struct chanspy_translation_helper * | csth | |||
) | [static] |
Definition at line 233 of file app_chanspy.c.
References ast_channel_setoption(), AST_OPTION_TXGAIN, ast_channel_spy::read_vol_adjustment, chanspy_translation_helper::spy, chanspy_translation_helper::volfactor, and ast_channel_spy::write_vol_adjustment.
Referenced by channel_spy().
00234 { 00235 signed char volume_adjust = volfactor_map[csth->volfactor + 4]; 00236 00237 if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0)) 00238 csth->volfactor = 0; 00239 csth->spy.read_vol_adjustment = csth->volfactor; 00240 csth->spy.write_vol_adjustment = csth->volfactor; 00241 }
static void* spy_alloc | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 151 of file app_chanspy.c.
00152 { 00153 /* just store the data pointer in the channel structure */ 00154 return data; 00155 }
static int spy_generate | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 162 of file app_chanspy.c.
References ast_channel_spy_read_frame(), ast_frfree(), ast_mutex_lock(), ast_mutex_unlock(), ast_write(), CHANSPY_RUNNING, f, chanspy_translation_helper::fd, ast_channel_spy::lock, chanspy_translation_helper::spy, and ast_channel_spy::status.
00163 { 00164 struct chanspy_translation_helper *csth = data; 00165 struct ast_frame *f; 00166 00167 if (csth->spy.status != CHANSPY_RUNNING) 00168 /* Channel is already gone more than likely */ 00169 return -1; 00170 00171 ast_mutex_lock(&csth->spy.lock); 00172 f = ast_channel_spy_read_frame(&csth->spy, samples); 00173 ast_mutex_unlock(&csth->spy.lock); 00174 00175 if (!f) 00176 return 0; 00177 00178 if (ast_write(chan, f)) { 00179 ast_frfree(f); 00180 return -1; 00181 } 00182 00183 if (csth->fd) 00184 write(csth->fd, f->data, f->datalen); 00185 00186 ast_frfree(f); 00187 00188 return 0; 00189 }
static void spy_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
static int start_spying | ( | struct ast_channel * | chan, | |
struct ast_channel * | spychan, | |||
struct ast_channel_spy * | spy | |||
) | [static] |
Definition at line 197 of file app_chanspy.c.
References ast_bridged_channel(), ast_channel_lock, ast_channel_spy_add(), ast_channel_unlock, AST_FLAG_NBRIDGE, ast_log(), ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, and LOG_NOTICE.
Referenced by channel_spy().
00198 { 00199 int res; 00200 struct ast_channel *peer; 00201 00202 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name); 00203 00204 ast_channel_lock(chan); 00205 res = ast_channel_spy_add(chan, spy); 00206 ast_channel_unlock(chan); 00207 00208 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) 00209 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00210 00211 return res; 00212 }
static int unload_module | ( | void | ) | [static] |
Definition at line 726 of file app_chanspy.c.
References ast_module_user_hangup_all, and ast_unregister_application().
00727 { 00728 int res = 0; 00729 00730 res |= ast_unregister_application(app_chan); 00731 res |= ast_unregister_application(app_ext); 00732 00733 ast_module_user_hangup_all(); 00734 00735 return res; 00736 }
const char* app_chan = "ChanSpy" [static] |
Definition at line 57 of file app_chanspy.c.
const char* app_ext = "ExtenSpy" [static] |
Definition at line 88 of file app_chanspy.c.
enum { ... } chanspy_opt_args |
enum { ... } chanspy_opt_flags |
const char* desc_chan [static] |
Definition at line 58 of file app_chanspy.c.
const char* desc_ext [static] |
Definition at line 89 of file app_chanspy.c.
struct ast_generator spygen [static] |
Initial value:
{ .alloc = spy_alloc, .release = spy_release, .generate = spy_generate, }
Definition at line 191 of file app_chanspy.c.
Referenced by channel_spy().
const char* tdesc = "Listen to a channel, and optionally whisper into it" [static] |
Definition at line 56 of file app_chanspy.c.
signed char volfactor_map[] [static] |
Definition at line 217 of file app_chanspy.c.