#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "asterisk.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"
Go to the source code of this file.
Data Structures | |
struct | chanspy_translation_helper |
Defines | |
#define | ALL_DONE(u, ret) LOCAL_USER_REMOVE(u); return ret; |
#define | AST_NAME_STRLEN 256 |
#define | get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0 |
Enumerations | |
enum | { OPTION_QUIET = (1 << 0), OPTION_BRIDGED = (1 << 1), OPTION_VOLUME = (1 << 2), OPTION_GROUP = (1 << 3), OPTION_RECORD = (1 << 4) } |
enum | { OPT_ARG_VOLUME = 0, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_ARRAY_SIZE } |
Functions | |
AST_APP_OPTIONS (chanspy_opts,{AST_APP_OPTION('q', OPTION_QUIET), AST_APP_OPTION('b', OPTION_BRIDGED), 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_MUTEX_DEFINE_STATIC (modlock) | |
int | channel_spy (struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd) |
int | chanspy_exec (struct ast_channel *chan, void *data) |
char * | description (void) |
Provides a description of the module. | |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
int | load_module (void) |
Initialize the module. | |
ast_channel * | local_channel_walk (struct ast_channel *chan) |
ast_channel * | local_get_channel_begin_name (char *name) |
void | set_volume (struct ast_channel *chan, struct chanspy_translation_helper *csth) |
void * | spy_alloc (struct ast_channel *chan, void *data) |
int | spy_generate (struct ast_channel *chan, void *data, int len, int samples) |
void | spy_release (struct ast_channel *chan, void *data) |
int | start_spying (struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy) |
void | stop_spying (struct ast_channel *chan, struct ast_channel_spy *spy) |
int | unload_module (void) |
Cleanup all module structures, sockets, etc. | |
int | usecount (void) |
Provides a usecount. | |
Variables | |
const char * | app = "ChanSpy" |
enum { ... } | chanspy_opt_args |
enum { ... } | chanspy_opt_flags |
const char * | chanspy_spy_type = "ChanSpy" |
const char * | desc |
LOCAL_USER_DECL | |
ast_generator | spygen |
STANDARD_LOCAL_USER | |
const char * | synopsis = "Listen to the audio of an active channel\n" |
signed char | volfactor_map [] |
Definition in file app_chanspy.c.
|
Definition at line 52 of file app_chanspy.c. Referenced by _while_exec(), chanspy_exec(), and execif_exec(). |
|
Definition at line 51 of file app_chanspy.c. Referenced by chanspy_exec(). |
|
Definition at line 53 of file app_chanspy.c. Referenced by mixmonitor_exec(). |
|
Definition at line 83 of file app_chanspy.c. 00083 { 00084 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */ 00085 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */ 00086 OPTION_VOLUME = (1 << 2), /* Specify initial volume */ 00087 OPTION_GROUP = (1 << 3), /* Only look at channels in group */ 00088 OPTION_RECORD = (1 << 4), /* Record */ 00089 } chanspy_opt_flags;
|
|
Definition at line 91 of file app_chanspy.c. 00091 { 00092 OPT_ARG_VOLUME = 0, 00093 OPT_ARG_GROUP, 00094 OPT_ARG_RECORD, 00095 OPT_ARG_ARRAY_SIZE, 00096 } chanspy_opt_args;
|
|
|
|
|
|
Definition at line 251 of file app_chanspy.c. References ast_activate_generator(), ast_check_hangup(), ast_deactivate_generator(), ast_frfree(), ast_mutex_destroy(), ast_mutex_init(), ast_read(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_verbose(), ast_waitfor(), CHANSPY_FORMAT_AUDIO, CHANSPY_MIXAUDIO, CHANSPY_RUNNING, CHANSPY_TRIGGER_NONE, ast_channel_spy_queue::format, ast_frame::frametype, ast_channel_spy::lock, ast_channel::name, name, option_verbose, ast_channel_spy::read_queue, ast_channel_spy::read_vol_adjustment, set_volume(), chanspy_translation_helper::spy, spygen, start_spying(), stop_spying(), ast_frame::subclass, ast_channel_spy::type, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, chanspy_translation_helper::volfactor, and ast_channel_spy::write_vol_adjustment. Referenced by chanspy_exec(). 00252 { 00253 struct chanspy_translation_helper csth; 00254 int running, res = 0, x = 0; 00255 char inp[24]; 00256 char *name=NULL; 00257 struct ast_frame *f; 00258 00259 running = (chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee)); 00260 00261 if (running) { 00262 memset(inp, 0, sizeof(inp)); 00263 name = ast_strdupa(spyee->name); 00264 if (option_verbose >= 2) 00265 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name); 00266 00267 memset(&csth, 0, sizeof(csth)); 00268 ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO); 00269 ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE); 00270 ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO); 00271 csth.spy.type = chanspy_spy_type; 00272 csth.spy.status = CHANSPY_RUNNING; 00273 csth.spy.read_queue.format = AST_FORMAT_SLINEAR; 00274 csth.spy.write_queue.format = AST_FORMAT_SLINEAR; 00275 ast_mutex_init(&csth.spy.lock); 00276 csth.volfactor = *volfactor; 00277 set_volume(chan, &csth); 00278 csth.spy.read_vol_adjustment = csth.volfactor; 00279 csth.spy.write_vol_adjustment = csth.volfactor; 00280 csth.fd = fd; 00281 00282 if (start_spying(spyee, chan, &csth.spy)) 00283 running = 0; 00284 } 00285 00286 if (running) { 00287 running = 1; 00288 ast_activate_generator(chan, &spygen, &csth); 00289 00290 while (csth.spy.status == CHANSPY_RUNNING && 00291 chan && !ast_check_hangup(chan) && 00292 spyee && 00293 !ast_check_hangup(spyee) && 00294 running == 1 && 00295 (res = ast_waitfor(chan, -1) > -1)) { 00296 if ((f = ast_read(chan))) { 00297 res = 0; 00298 if (f->frametype == AST_FRAME_DTMF) { 00299 res = f->subclass; 00300 } 00301 ast_frfree(f); 00302 if (!res) { 00303 continue; 00304 } 00305 } else { 00306 break; 00307 } 00308 if (x == sizeof(inp)) { 00309 x = 0; 00310 } 00311 if (res < 0) { 00312 running = -1; 00313 } 00314 if (res == 0) { 00315 continue; 00316 } else if (res == '*') { 00317 running = 0; 00318 } else if (res == '#') { 00319 if (!ast_strlen_zero(inp)) { 00320 running = x ? atoi(inp) : -1; 00321 break; 00322 } else { 00323 (*volfactor)++; 00324 if (*volfactor > 4) { 00325 *volfactor = -4; 00326 } 00327 if (option_verbose > 2) { 00328 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor); 00329 } 00330 csth.volfactor = *volfactor; 00331 set_volume(chan, &csth); 00332 csth.spy.read_vol_adjustment = csth.volfactor; 00333 csth.spy.write_vol_adjustment = csth.volfactor; 00334 } 00335 } else if (res >= 48 && res <= 57) { 00336 inp[x++] = res; 00337 } 00338 } 00339 ast_deactivate_generator(chan); 00340 stop_spying(spyee, &csth.spy); 00341 00342 if (option_verbose >= 2) { 00343 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name); 00344 } 00345 } else { 00346 running = 0; 00347 } 00348 00349 ast_mutex_destroy(&csth.spy.lock); 00350 00351 return running; 00352 }
|
|
Definition at line 354 of file app_chanspy.c. References ALL_DONE, ast_answer(), ast_app_parse_options(), ast_app_separate_args(), ast_bridged_channel(), ast_channel_setoption(), ast_check_hangup(), ast_clear_flag, ast_config_AST_MONITOR_DIR, ast_fileexists(), AST_FLAG_SPYING, AST_FORMAT_SLINEAR, ast_log(), AST_NAME_STRLEN, AST_OPTION_TXGAIN, ast_say_character_str(), ast_say_digits(), ast_set_flag, ast_set_read_format(), ast_set_write_format(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), ast_waitstream(), channel_spy(), ast_channel::language, local_channel_walk(), local_get_channel_begin_name(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_channel::name, name, OPTION_BRIDGED, OPTION_GROUP, OPTION_QUIET, OPTION_RECORD, OPTION_VOLUME, pbx_builtin_getvar_helper(), ast_channel::readformat, and ast_channel::writeformat. Referenced by load_module(). 00355 { 00356 struct localuser *u; 00357 struct ast_channel *peer=NULL, *prev=NULL; 00358 char name[AST_NAME_STRLEN], 00359 peer_name[AST_NAME_STRLEN + 5], 00360 *args, 00361 *ptr = NULL, 00362 *options = NULL, 00363 *spec = NULL, 00364 *argv[5], 00365 *mygroup = NULL, 00366 *recbase = NULL; 00367 int res = -1, 00368 volfactor = 0, 00369 silent = 0, 00370 argc = 0, 00371 bronly = 0, 00372 chosen = 0, 00373 count=0, 00374 waitms = 100, 00375 num = 0, 00376 oldrf = 0, 00377 oldwf = 0, 00378 fd = 0; 00379 struct ast_flags flags; 00380 signed char zero_volume = 0; 00381 00382 if (!(args = ast_strdupa((char *)data))) { 00383 ast_log(LOG_ERROR, "Out of memory!\n"); 00384 return -1; 00385 } 00386 00387 LOCAL_USER_ADD(u); 00388 00389 oldrf = chan->readformat; 00390 oldwf = chan->writeformat; 00391 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) { 00392 ast_log(LOG_ERROR, "Could Not Set Read Format.\n"); 00393 LOCAL_USER_REMOVE(u); 00394 return -1; 00395 } 00396 00397 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00398 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00399 LOCAL_USER_REMOVE(u); 00400 return -1; 00401 } 00402 00403 ast_answer(chan); 00404 00405 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ 00406 00407 if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00408 spec = argv[0]; 00409 if ( argc > 1) { 00410 options = argv[1]; 00411 } 00412 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) { 00413 spec = NULL; 00414 } 00415 } 00416 00417 if (options) { 00418 char *opts[OPT_ARG_ARRAY_SIZE]; 00419 ast_app_parse_options(chanspy_opts, &flags, opts, options); 00420 if (ast_test_flag(&flags, OPTION_GROUP)) { 00421 mygroup = opts[1]; 00422 } 00423 if (ast_test_flag(&flags, OPTION_RECORD)) { 00424 if (!(recbase = opts[2])) { 00425 recbase = "chanspy"; 00426 } 00427 } 00428 silent = ast_test_flag(&flags, OPTION_QUIET); 00429 bronly = ast_test_flag(&flags, OPTION_BRIDGED); 00430 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[1]) { 00431 int vol; 00432 00433 if ((sscanf(opts[0], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00434 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00435 else 00436 volfactor = vol; 00437 } 00438 } 00439 00440 if (recbase) { 00441 char filename[512]; 00442 snprintf(filename,sizeof(filename),"%s/%s.%d.raw",ast_config_AST_MONITOR_DIR, recbase, (int)time(NULL)); 00443 if ((fd = open(filename, O_CREAT | O_WRONLY, O_TRUNC, 0644)) <= 0) { 00444 ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename); 00445 fd = 0; 00446 } 00447 } 00448 00449 for(;;) { 00450 if (!silent) { 00451 res = ast_streamfile(chan, "beep", chan->language); 00452 if (!res) 00453 res = ast_waitstream(chan, ""); 00454 if (res < 0) { 00455 ast_clear_flag(chan, AST_FLAG_SPYING); 00456 break; 00457 } 00458 } 00459 00460 count = 0; 00461 res = ast_waitfordigit(chan, waitms); 00462 if (res < 0) { 00463 ast_clear_flag(chan, AST_FLAG_SPYING); 00464 break; 00465 } 00466 00467 peer = local_channel_walk(NULL); 00468 prev=NULL; 00469 while(peer) { 00470 if (peer != chan) { 00471 char *group = NULL; 00472 int igrp = 1; 00473 00474 if (peer == prev && !chosen) { 00475 break; 00476 } 00477 chosen = 0; 00478 group = pbx_builtin_getvar_helper(peer, "SPYGROUP"); 00479 if (mygroup) { 00480 if (!group || strcmp(mygroup, group)) { 00481 igrp = 0; 00482 } 00483 } 00484 00485 if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) && 00486 !strncasecmp(peer->name, spec, strlen(spec)))))) { 00487 if (peer && (!bronly || ast_bridged_channel(peer)) && 00488 !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) { 00489 int x = 0; 00490 strncpy(peer_name, "spy-", 5); 00491 strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN); 00492 ptr = strchr(peer_name, '/'); 00493 *ptr = '\0'; 00494 ptr++; 00495 for (x = 0 ; x < strlen(peer_name) ; x++) { 00496 if (peer_name[x] == '/') { 00497 break; 00498 } 00499 peer_name[x] = tolower(peer_name[x]); 00500 } 00501 00502 if (!silent) { 00503 if (ast_fileexists(peer_name, NULL, NULL) != -1) { 00504 res = ast_streamfile(chan, peer_name, chan->language); 00505 if (!res) 00506 res = ast_waitstream(chan, ""); 00507 if (res) 00508 break; 00509 } else 00510 res = ast_say_character_str(chan, peer_name, "", chan->language); 00511 if ((num=atoi(ptr))) 00512 ast_say_digits(chan, atoi(ptr), "", chan->language); 00513 } 00514 count++; 00515 prev = peer; 00516 res = channel_spy(chan, peer, &volfactor, fd); 00517 if (res == -1) { 00518 break; 00519 } else if (res > 1 && spec) { 00520 snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res); 00521 if ((peer = local_get_channel_begin_name(name))) { 00522 chosen = 1; 00523 } 00524 continue; 00525 } 00526 } 00527 } 00528 } 00529 if ((peer = local_channel_walk(peer)) == NULL) { 00530 break; 00531 } 00532 } 00533 waitms = count ? 100 : 5000; 00534 } 00535 00536 00537 if (fd > 0) { 00538 close(fd); 00539 } 00540 00541 if (oldrf && ast_set_read_format(chan, oldrf) < 0) { 00542 ast_log(LOG_ERROR, "Could Not Set Read Format.\n"); 00543 } 00544 00545 if (oldwf && ast_set_write_format(chan, oldwf) < 0) { 00546 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00547 } 00548 00549 ast_clear_flag(chan, AST_FLAG_SPYING); 00550 00551 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 00552 00553 ALL_DONE(u, res); 00554 }
|
|
Provides a description of the module.
Definition at line 572 of file app_chanspy.c. 00573 { 00574 return (char *) synopsis; 00575 }
|
|
Returns the ASTERISK_GPL_KEY. This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:
char *key(void) { return ASTERISK_GPL_KEY; }
Definition at line 584 of file app_chanspy.c. 00585 {
00586 return ASTERISK_GPL_KEY;
00587 }
|
|
Initialize the module. Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
Definition at line 567 of file app_chanspy.c. References app, ast_register_application(), chanspy_exec(), desc, and synopsis. 00568 { 00569 return ast_register_application(app, chanspy_exec, synopsis, desc); 00570 }
|
|
Definition at line 116 of file app_chanspy.c. References ast_channel_walk_locked(), ast_mutex_lock(), ast_mutex_unlock(), and ast_channel::lock. Referenced by chanspy_exec(), and local_get_channel_begin_name(). 00117 { 00118 struct ast_channel *ret; 00119 ast_mutex_lock(&modlock); 00120 if ((ret = ast_channel_walk_locked(chan))) { 00121 ast_mutex_unlock(&ret->lock); 00122 } 00123 ast_mutex_unlock(&modlock); 00124 return ret; 00125 }
|
|
Definition at line 127 of file app_chanspy.c. References ast_mutex_lock(), ast_mutex_unlock(), local_channel_walk(), name, and ast_channel::name. Referenced by chanspy_exec(). 00128 { 00129 struct ast_channel *chan, *ret = NULL; 00130 ast_mutex_lock(&modlock); 00131 chan = local_channel_walk(NULL); 00132 while (chan) { 00133 if (!strncmp(chan->name, name, strlen(name))) { 00134 ret = chan; 00135 break; 00136 } 00137 chan = local_channel_walk(chan); 00138 } 00139 ast_mutex_unlock(&modlock); 00140 00141 return ret; 00142 }
|
|
Definition at line 243 of file app_chanspy.c. References ast_channel_setoption(), AST_OPTION_TXGAIN, chanspy_translation_helper::volfactor, and volfactor_map. Referenced by channel_spy(). 00244 { 00245 signed char volume_adjust = volfactor_map[csth->volfactor + 4]; 00246 00247 if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0)) 00248 csth->volfactor = 0; 00249 }
|
|
Definition at line 144 of file app_chanspy.c. 00145 { 00146 /* just store the data pointer in the channel structure */ 00147 return data; 00148 }
|
|
Definition at line 155 of file app_chanspy.c. References ast_channel_spy_read_frame(), ast_frfree(), ast_mutex_lock(), ast_mutex_unlock(), ast_write(), ast_frame::data, ast_frame::datalen, chanspy_translation_helper::fd, ast_channel_spy::lock, and chanspy_translation_helper::spy. 00156 { 00157 struct chanspy_translation_helper *csth = data; 00158 struct ast_frame *f; 00159 00160 if (csth->spy.status != CHANSPY_RUNNING) 00161 /* Channel is already gone more than likely */ 00162 return -1; 00163 00164 ast_mutex_lock(&csth->spy.lock); 00165 f = ast_channel_spy_read_frame(&csth->spy, samples); 00166 ast_mutex_unlock(&csth->spy.lock); 00167 00168 if (!f) 00169 return 0; 00170 00171 if (ast_write(chan, f)) { 00172 ast_frfree(f); 00173 return -1; 00174 } 00175 00176 if (csth->fd) 00177 write(csth->fd, f->data, f->datalen); 00178 00179 ast_frfree(f); 00180 00181 return 0; 00182 }
|
|
Definition at line 150 of file app_chanspy.c. 00151 {
00152 /* nothing to do */
00153 }
|
|
Definition at line 191 of file app_chanspy.c. References ast_bridged_channel(), ast_channel_spy_add(), AST_FLAG_NBRIDGE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, ast_channel::lock, LOG_NOTICE, and ast_channel::name. Referenced by channel_spy(). 00192 { 00193 int res; 00194 struct ast_channel *peer; 00195 00196 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name); 00197 00198 ast_mutex_lock(&chan->lock); 00199 res = ast_channel_spy_add(chan, spy); 00200 ast_mutex_unlock(&chan->lock); 00201 00202 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) { 00203 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00204 } 00205 00206 return res; 00207 }
|
|
Definition at line 209 of file app_chanspy.c. References ast_channel_spy_remove(), ast_mutex_lock(), ast_mutex_unlock(), and ast_channel::lock. Referenced by channel_spy(). 00210 { 00211 /* If our status has changed to DONE, then the channel we're spying on is gone.... 00212 DON'T TOUCH IT!!! RUN AWAY!!! */ 00213 if (spy->status == CHANSPY_DONE) 00214 return; 00215 00216 if (!chan) 00217 return; 00218 00219 ast_mutex_lock(&chan->lock); 00220 ast_channel_spy_remove(chan, spy); 00221 ast_mutex_unlock(&chan->lock); 00222 };
|
|
Cleanup all module structures, sockets, etc. This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).
Definition at line 556 of file app_chanspy.c. References app, and ast_unregister_application(). 00557 { 00558 int res; 00559 00560 res = ast_unregister_application(app); 00561 00562 STANDARD_HANGUP_LOCALUSERS; 00563 00564 return res; 00565 }
|
|
Provides a usecount. This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.
Definition at line 577 of file app_chanspy.c. References STANDARD_USECOUNT. 00578 { 00579 int res; 00580 STANDARD_USECOUNT(res); 00581 return res; 00582 }
|
|
Definition at line 56 of file app_chanspy.c. Referenced by load_module(), and unload_module(). |
|
|
|
|
|
Definition at line 81 of file app_chanspy.c. |
|
Definition at line 57 of file app_chanspy.c. Referenced by load_module(). |
|
Definition at line 107 of file app_chanspy.c. |
|
Initial value: { .alloc = spy_alloc, .release = spy_release, .generate = spy_generate, } Definition at line 185 of file app_chanspy.c. Referenced by channel_spy(). |
|
Definition at line 106 of file app_chanspy.c. |
|
Definition at line 55 of file app_chanspy.c. Referenced by load_module(). |
|
Definition at line 227 of file app_chanspy.c. Referenced by set_volume(). |