#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 /* If a channel still exists on our spy structure then we need to remove ourselves */ 00391 if (csth.spy.chan) { 00392 csth.spy.status = CHANSPY_DONE; 00393 ast_channel_lock(csth.spy.chan); 00394 ast_channel_spy_remove(csth.spy.chan, &csth.spy); 00395 ast_channel_unlock(csth.spy.chan); 00396 } 00397 ast_channel_spy_free(&csth.spy); 00398 00399 if (option_verbose >= 2) 00400 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name); 00401 00402 return running; 00403 }
static int chanspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 557 of file app_chanspy.c.
References ast_app_parse_options(), ast_app_separate_args(), ast_config_AST_MONITOR_DIR, 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().
00558 { 00559 struct ast_module_user *u; 00560 char *options = NULL; 00561 char *spec = NULL; 00562 char *argv[2]; 00563 char *mygroup = NULL; 00564 char *recbase = NULL; 00565 int fd = 0; 00566 struct ast_flags flags; 00567 int oldwf = 0; 00568 int argc = 0; 00569 int volfactor = 0; 00570 int res; 00571 00572 data = ast_strdupa(data); 00573 00574 u = ast_module_user_add(chan); 00575 00576 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00577 spec = argv[0]; 00578 if (argc > 1) 00579 options = argv[1]; 00580 00581 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) 00582 spec = NULL; 00583 } 00584 00585 if (options) { 00586 char *opts[OPT_ARG_ARRAY_SIZE]; 00587 00588 ast_app_parse_options(spy_opts, &flags, opts, options); 00589 if (ast_test_flag(&flags, OPTION_GROUP)) 00590 mygroup = opts[OPT_ARG_GROUP]; 00591 00592 if (ast_test_flag(&flags, OPTION_RECORD) && 00593 !(recbase = opts[OPT_ARG_RECORD])) 00594 recbase = "chanspy"; 00595 00596 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00597 int vol; 00598 00599 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00600 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00601 else 00602 volfactor = vol; 00603 } 00604 00605 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00606 ast_set_flag(&flags, OPTION_WHISPER); 00607 } 00608 00609 oldwf = chan->writeformat; 00610 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00611 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00612 ast_module_user_remove(u); 00613 return -1; 00614 } 00615 00616 if (recbase) { 00617 char filename[512]; 00618 00619 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00620 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00621 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00622 fd = 0; 00623 } 00624 } 00625 00626 res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL); 00627 00628 if (fd) 00629 close(fd); 00630 00631 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00632 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00633 00634 ast_module_user_remove(u); 00635 00636 return res; 00637 }
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 427 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().
00430 { 00431 struct ast_channel *peer, *prev, *next; 00432 char nameprefix[AST_NAME_STRLEN]; 00433 char peer_name[AST_NAME_STRLEN + 5]; 00434 signed char zero_volume = 0; 00435 int waitms; 00436 int res; 00437 char *ptr; 00438 int num; 00439 00440 if (chan->_state != AST_STATE_UP) 00441 ast_answer(chan); 00442 00443 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ 00444 00445 waitms = 100; 00446 00447 for (;;) { 00448 if (!ast_test_flag(flags, OPTION_QUIET)) { 00449 res = ast_streamfile(chan, "beep", chan->language); 00450 if (!res) 00451 res = ast_waitstream(chan, ""); 00452 else if (res < 0) { 00453 ast_clear_flag(chan, AST_FLAG_SPYING); 00454 break; 00455 } 00456 } 00457 00458 res = ast_waitfordigit(chan, waitms); 00459 if (res < 0) { 00460 ast_clear_flag(chan, AST_FLAG_SPYING); 00461 break; 00462 } 00463 00464 /* reset for the next loop around, unless overridden later */ 00465 waitms = 100; 00466 peer = prev = next = NULL; 00467 00468 for (peer = next_channel(peer, spec, exten, context); 00469 peer; 00470 prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) { 00471 const char *group; 00472 int igrp = !mygroup; 00473 char *groups[25]; 00474 int num_groups = 0; 00475 char *dup_group; 00476 int x; 00477 char *s; 00478 00479 if (peer == prev) 00480 break; 00481 00482 if (peer == chan) 00483 continue; 00484 00485 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) 00486 continue; 00487 00488 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) 00489 continue; 00490 00491 if (mygroup) { 00492 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { 00493 dup_group = ast_strdupa(group); 00494 num_groups = ast_app_separate_args(dup_group, ':', groups, 00495 sizeof(groups) / sizeof(groups[0])); 00496 } 00497 00498 for (x = 0; x < num_groups; x++) { 00499 if (!strcmp(mygroup, groups[x])) { 00500 igrp = 1; 00501 break; 00502 } 00503 } 00504 } 00505 00506 if (!igrp) 00507 continue; 00508 00509 strcpy(peer_name, "spy-"); 00510 strncat(peer_name, peer->name, AST_NAME_STRLEN); 00511 ptr = strchr(peer_name, '/'); 00512 *ptr++ = '\0'; 00513 00514 for (s = peer_name; s < ptr; s++) 00515 *s = tolower(*s); 00516 00517 if (!ast_test_flag(flags, OPTION_QUIET)) { 00518 if (ast_fileexists(peer_name, NULL, NULL) != -1) { 00519 res = ast_streamfile(chan, peer_name, chan->language); 00520 if (!res) 00521 res = ast_waitstream(chan, ""); 00522 if (res) 00523 break; 00524 } else 00525 res = ast_say_character_str(chan, peer_name, "", chan->language); 00526 if ((num = atoi(ptr))) 00527 ast_say_digits(chan, atoi(ptr), "", chan->language); 00528 } 00529 00530 waitms = 5000; 00531 res = channel_spy(chan, peer, &volfactor, fd, flags); 00532 00533 if (res == -1) { 00534 break; 00535 } else if (res > 1 && spec) { 00536 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); 00537 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { 00538 ast_channel_unlock(next); 00539 } else { 00540 /* stay on this channel */ 00541 next = peer; 00542 } 00543 peer = NULL; 00544 } 00545 } 00546 if (res == -1) 00547 break; 00548 } 00549 00550 ast_clear_flag(chan, AST_FLAG_SPYING); 00551 00552 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 00553 00554 return res; 00555 }
static int extenspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 639 of file app_chanspy.c.
References ast_app_parse_options(), ast_app_separate_args(), ast_config_AST_MONITOR_DIR, 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().
00640 { 00641 struct ast_module_user *u; 00642 char *options = NULL; 00643 char *exten = NULL; 00644 char *context = NULL; 00645 char *argv[2]; 00646 char *mygroup = NULL; 00647 char *recbase = NULL; 00648 int fd = 0; 00649 struct ast_flags flags; 00650 int oldwf = 0; 00651 int argc = 0; 00652 int volfactor = 0; 00653 int res; 00654 00655 data = ast_strdupa(data); 00656 00657 u = ast_module_user_add(chan); 00658 00659 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00660 context = argv[0]; 00661 if (!ast_strlen_zero(argv[0])) 00662 exten = strsep(&context, "@"); 00663 if (ast_strlen_zero(context)) 00664 context = ast_strdupa(chan->context); 00665 if (argc > 1) 00666 options = argv[1]; 00667 } 00668 00669 if (options) { 00670 char *opts[OPT_ARG_ARRAY_SIZE]; 00671 00672 ast_app_parse_options(spy_opts, &flags, opts, options); 00673 if (ast_test_flag(&flags, OPTION_GROUP)) 00674 mygroup = opts[OPT_ARG_GROUP]; 00675 00676 if (ast_test_flag(&flags, OPTION_RECORD) && 00677 !(recbase = opts[OPT_ARG_RECORD])) 00678 recbase = "chanspy"; 00679 00680 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00681 int vol; 00682 00683 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00684 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00685 else 00686 volfactor = vol; 00687 } 00688 00689 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00690 ast_set_flag(&flags, OPTION_WHISPER); 00691 } 00692 00693 oldwf = chan->writeformat; 00694 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00695 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00696 ast_module_user_remove(u); 00697 return -1; 00698 } 00699 00700 if (recbase) { 00701 char filename[512]; 00702 00703 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00704 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00705 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00706 fd = 0; 00707 } 00708 } 00709 00710 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context); 00711 00712 if (fd) 00713 close(fd); 00714 00715 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00716 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00717 00718 ast_module_user_remove(u); 00719 00720 return res; 00721 }
static int load_module | ( | void | ) | [static] |
Definition at line 735 of file app_chanspy.c.
References ast_register_application(), chanspy_exec(), and extenspy_exec().
00736 { 00737 int res = 0; 00738 00739 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan); 00740 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext); 00741 00742 return res; 00743 }
static struct ast_channel* next_channel | ( | const struct ast_channel * | last, | |
const char * | spec, | |||
const char * | exten, | |||
const char * | context | |||
) | [static] |
Definition at line 405 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().
00407 { 00408 struct ast_channel *this; 00409 00410 redo: 00411 if (spec) 00412 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec)); 00413 else if (exten) 00414 this = ast_walk_channel_by_exten_locked(last, exten, context); 00415 else 00416 this = ast_channel_walk_locked(last); 00417 00418 if (this) { 00419 ast_channel_unlock(this); 00420 if (!strncmp(this->name, "Zap/pseudo", 10)) 00421 goto redo; 00422 } 00423 00424 return this; 00425 }
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 723 of file app_chanspy.c.
References ast_module_user_hangup_all, and ast_unregister_application().
00724 { 00725 int res = 0; 00726 00727 res |= ast_unregister_application(app_chan); 00728 res |= ast_unregister_application(app_ext); 00729 00730 ast_module_user_hangup_all(); 00731 00732 return res; 00733 }
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.