Fri Aug 24 02:22:28 2007

Asterisk developer's documentation


app_chanspy.c File Reference

ChanSpy: Listen in on any channel. More...

#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_channelnext_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 []


Detailed Description

ChanSpy: Listen in on any channel.

Author:
Anthony Minessale II <anthmct@yahoo.com>

Definition in file app_chanspy.c.


Define Documentation

#define AST_NAME_STRLEN   256

Definition at line 54 of file app_chanspy.c.

Referenced by common_exec().


Enumeration Type Documentation

anonymous enum

Enumerator:
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

Enumerator:
OPT_ARG_VOLUME 
OPT_ARG_GROUP 
OPT_ARG_RECORD 
OPT_ARG_ARRAY_SIZE 

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;


Function Documentation

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]

Definition at line 157 of file app_chanspy.c.

00158 {
00159    /* nothing to do */
00160 }

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 }


Variable Documentation

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.


Generated on Fri Aug 24 02:22:29 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1