Mon May 14 04:43:27 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    /* 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]

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 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 }


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 Mon May 14 04:43:28 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1