2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
5 * Copyright (C) 2005 - 2006, Digium, Inc.
7 * A license has been granted to Digium (via disclaimer) for the use of
10 * See http://www.asterisk.org for more information about
11 * the Asterisk project. Please do not directly contact
12 * any of the maintainers of this project for assistance;
13 * the project provides a web site, mailing lists and IRC
14 * channels for your use.
16 * This program is free software, distributed under the terms of
17 * the GNU General Public License Version 2. See the LICENSE file
18 * at the top of the source tree.
23 * \brief ChanSpy: Listen in on any channel.
25 * \author Anthony Minessale II <anthmct@yahoo.com>
27 * \ingroup applications
32 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
40 #include "asterisk/file.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/chanspy.h"
44 #include "asterisk/features.h"
45 #include "asterisk/options.h"
46 #include "asterisk/app.h"
47 #include "asterisk/utils.h"
48 #include "asterisk/say.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/translate.h"
51 #include "asterisk/module.h"
52 #include "asterisk/lock.h"
54 #define AST_NAME_STRLEN 256
56 static const char *tdesc
= "Listen to a channel, and optionally whisper into it";
57 static const char *app_chan
= "ChanSpy";
58 static const char *desc_chan
=
59 " ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
60 "audio from an Asterisk channel. This includes the audio coming in and\n"
61 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
62 "only channels beginning with this string will be spied upon.\n"
63 " While spying, the following actions may be performed:\n"
64 " - Dialing # cycles the volume level.\n"
65 " - Dialing * will stop spying and look for another channel to spy on.\n"
66 " - Dialing a series of digits followed by # builds a channel name to append\n"
67 " to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
68 " the digits '1234#' while spying will begin spying on the channel\n"
71 " b - Only spy on channels involved in a bridged call.\n"
72 " g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
73 " contain 'grp' in an optional : delimited list.\n"
74 " q - Don't play a beep when beginning to spy on a channel, or speak the\n"
75 " selected channel name.\n"
76 " r[(basename)] - Record the session to the monitor spool directory. An\n"
77 " optional base for the filename may be specified. The\n"
78 " default is 'chanspy'.\n"
79 " v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
80 " negative value refers to a quieter setting.\n"
81 " w - Enable 'whisper' mode, so the spying channel can talk to\n"
82 " the spied-on channel.\n"
83 " W - Enable 'private whisper' mode, so the spying channel can\n"
84 " talk to the spied-on channel but cannot listen to that\n"
88 static const char *app_ext
= "ExtenSpy";
89 static const char *desc_ext
=
90 " ExtenSpy(exten[@context][|options]): This application is used to listen to the\n"
91 "audio from an Asterisk channel. This includes the audio coming in and\n"
92 "out of the channel being spied on. Only channels created by outgoing calls for the\n"
93 "specified extension will be selected for spying. If the optional context is not\n"
94 "supplied, the current channel's context will be used.\n"
95 " While spying, the following actions may be performed:\n"
96 " - Dialing # cycles the volume level.\n"
97 " - Dialing * will stop spying and look for another channel to spy on.\n"
99 " b - Only spy on channels involved in a bridged call.\n"
100 " g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
101 " contain 'grp' in an optional : delimited list.\n"
102 " q - Don't play a beep when beginning to spy on a channel, or speak the\n"
103 " selected channel name.\n"
104 " r[(basename)] - Record the session to the monitor spool directory. An\n"
105 " optional base for the filename may be specified. The\n"
106 " default is 'chanspy'.\n"
107 " v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
108 " negative value refers to a quieter setting.\n"
109 " w - Enable 'whisper' mode, so the spying channel can talk to\n"
110 " the spied-on channel.\n"
111 " W - Enable 'private whisper' mode, so the spying channel can\n"
112 " talk to the spied-on channel but cannot listen to that\n"
117 OPTION_QUIET
= (1 << 0), /* Quiet, no announcement */
118 OPTION_BRIDGED
= (1 << 1), /* Only look at bridged calls */
119 OPTION_VOLUME
= (1 << 2), /* Specify initial volume */
120 OPTION_GROUP
= (1 << 3), /* Only look at channels in group */
121 OPTION_RECORD
= (1 << 4),
122 OPTION_WHISPER
= (1 << 5),
123 OPTION_PRIVATE
= (1 << 6), /* Private Whisper mode */
133 AST_APP_OPTIONS(spy_opts
, {
134 AST_APP_OPTION('q', OPTION_QUIET
),
135 AST_APP_OPTION('b', OPTION_BRIDGED
),
136 AST_APP_OPTION('w', OPTION_WHISPER
),
137 AST_APP_OPTION('W', OPTION_PRIVATE
),
138 AST_APP_OPTION_ARG('v', OPTION_VOLUME
, OPT_ARG_VOLUME
),
139 AST_APP_OPTION_ARG('g', OPTION_GROUP
, OPT_ARG_GROUP
),
140 AST_APP_OPTION_ARG('r', OPTION_RECORD
, OPT_ARG_RECORD
),
144 struct chanspy_translation_helper
{
146 struct ast_channel_spy spy
;
151 static void *spy_alloc(struct ast_channel
*chan
, void *data
)
153 /* just store the data pointer in the channel structure */
157 static void spy_release(struct ast_channel
*chan
, void *data
)
162 static int spy_generate(struct ast_channel
*chan
, void *data
, int len
, int samples
)
164 struct chanspy_translation_helper
*csth
= data
;
167 if (csth
->spy
.status
!= CHANSPY_RUNNING
)
168 /* Channel is already gone more than likely */
171 ast_mutex_lock(&csth
->spy
.lock
);
172 f
= ast_channel_spy_read_frame(&csth
->spy
, samples
);
173 ast_mutex_unlock(&csth
->spy
.lock
);
178 if (ast_write(chan
, f
)) {
184 write(csth
->fd
, f
->data
, f
->datalen
);
191 static struct ast_generator spygen
= {
193 .release
= spy_release
,
194 .generate
= spy_generate
,
197 static int start_spying(struct ast_channel
*chan
, struct ast_channel
*spychan
, struct ast_channel_spy
*spy
)
200 struct ast_channel
*peer
;
202 ast_log(LOG_NOTICE
, "Attaching %s to %s\n", spychan
->name
, chan
->name
);
204 ast_channel_lock(chan
);
205 res
= ast_channel_spy_add(chan
, spy
);
206 ast_channel_unlock(chan
);
208 if (!res
&& ast_test_flag(chan
, AST_FLAG_NBRIDGE
) && (peer
= ast_bridged_channel(chan
)))
209 ast_softhangup(peer
, AST_SOFTHANGUP_UNBRIDGE
);
214 /* Map 'volume' levels from -4 through +4 into
215 decibel (dB) settings for channel drivers
217 static signed char volfactor_map
[] = {
229 /* attempt to set the desired gain adjustment via the channel driver;
230 if successful, clear it out of the csth structure so the
231 generator will not attempt to do the adjustment itself
233 static void set_volume(struct ast_channel
*chan
, struct chanspy_translation_helper
*csth
)
235 signed char volume_adjust
= volfactor_map
[csth
->volfactor
+ 4];
237 if (!ast_channel_setoption(chan
, AST_OPTION_TXGAIN
, &volume_adjust
, sizeof(volume_adjust
), 0))
239 csth
->spy
.read_vol_adjustment
= csth
->volfactor
;
240 csth
->spy
.write_vol_adjustment
= csth
->volfactor
;
243 static int channel_spy(struct ast_channel
*chan
, struct ast_channel
*spyee
, int *volfactor
, int fd
,
244 const struct ast_flags
*flags
)
246 struct chanspy_translation_helper csth
;
247 int running
= 0, res
, x
= 0;
251 struct ast_silence_generator
*silgen
= NULL
;
253 if (ast_check_hangup(chan
) || ast_check_hangup(spyee
))
256 name
= ast_strdupa(spyee
->name
);
257 if (option_verbose
>= 2)
258 ast_verbose(VERBOSE_PREFIX_2
"Spying on channel %s\n", name
);
260 memset(&csth
, 0, sizeof(csth
));
261 ast_set_flag(&csth
.spy
, CHANSPY_FORMAT_AUDIO
);
262 ast_set_flag(&csth
.spy
, CHANSPY_TRIGGER_NONE
);
263 ast_set_flag(&csth
.spy
, CHANSPY_MIXAUDIO
);
264 csth
.spy
.type
= "ChanSpy";
265 csth
.spy
.status
= CHANSPY_RUNNING
;
266 csth
.spy
.read_queue
.format
= AST_FORMAT_SLINEAR
;
267 csth
.spy
.write_queue
.format
= AST_FORMAT_SLINEAR
;
268 ast_mutex_init(&csth
.spy
.lock
);
269 csth
.volfactor
= *volfactor
;
270 set_volume(chan
, &csth
);
271 if (csth
.volfactor
) {
272 ast_set_flag(&csth
.spy
, CHANSPY_READ_VOLADJUST
);
273 csth
.spy
.read_vol_adjustment
= csth
.volfactor
;
274 ast_set_flag(&csth
.spy
, CHANSPY_WRITE_VOLADJUST
);
275 csth
.spy
.write_vol_adjustment
= csth
.volfactor
;
279 if (start_spying(spyee
, chan
, &csth
.spy
)) {
280 ast_mutex_destroy(&csth
.spy
.lock
);
284 if (ast_test_flag(flags
, OPTION_WHISPER
)) {
285 struct ast_filestream
*beepstream
;
286 int old_write_format
= 0;
288 ast_channel_whisper_start(csth
.spy
.chan
);
289 old_write_format
= chan
->writeformat
;
290 if ((beepstream
= ast_openstream_full(chan
, "beep", chan
->language
, 1))) {
293 while ((f
= ast_readframe(beepstream
))) {
294 ast_channel_whisper_feed(csth
.spy
.chan
, f
);
298 ast_closestream(beepstream
);
301 if (old_write_format
)
302 ast_set_write_format(chan
, old_write_format
);
305 if (ast_test_flag(flags
, OPTION_PRIVATE
))
306 silgen
= ast_channel_start_silence_generator(chan
);
308 ast_activate_generator(chan
, &spygen
, &csth
);
310 /* We can no longer rely on 'spyee' being an actual channel;
311 it can be hung up and freed out from under us. However, the
312 channel destructor will put NULL into our csth.spy.chan
313 field when that happens, so that is our signal that the spyee
314 channel has gone away.
317 /* Note: it is very important that the ast_waitfor() be the first
318 condition in this expression, so that if we wait for some period
319 of time before receiving a frame from our spying channel, we check
320 for hangup on the spied-on channel _after_ knowing that a frame
321 has arrived, since the spied-on channel could have gone away while
324 while ((res
= ast_waitfor(chan
, -1) > -1) &&
325 csth
.spy
.status
== CHANSPY_RUNNING
&&
327 if (!(f
= ast_read(chan
)) || ast_check_hangup(chan
)) {
332 if (ast_test_flag(flags
, OPTION_WHISPER
) &&
333 (f
->frametype
== AST_FRAME_VOICE
)) {
334 ast_channel_whisper_feed(csth
.spy
.chan
, f
);
339 res
= (f
->frametype
== AST_FRAME_DTMF
) ? f
->subclass
: 0;
344 if (x
== sizeof(inp
))
355 } else if (res
== '#') {
356 if (!ast_strlen_zero(inp
)) {
364 if (option_verbose
> 2)
365 ast_verbose(VERBOSE_PREFIX_3
"Setting spy volume on %s to %d\n", chan
->name
, *volfactor
);
366 csth
.volfactor
= *volfactor
;
367 set_volume(chan
, &csth
);
368 if (csth
.volfactor
) {
369 ast_set_flag(&csth
.spy
, CHANSPY_READ_VOLADJUST
);
370 csth
.spy
.read_vol_adjustment
= csth
.volfactor
;
371 ast_set_flag(&csth
.spy
, CHANSPY_WRITE_VOLADJUST
);
372 csth
.spy
.write_vol_adjustment
= csth
.volfactor
;
374 ast_clear_flag(&csth
.spy
, CHANSPY_READ_VOLADJUST
);
375 ast_clear_flag(&csth
.spy
, CHANSPY_WRITE_VOLADJUST
);
377 } else if (res
>= '0' && res
<= '9') {
382 if (ast_test_flag(flags
, OPTION_WHISPER
) && csth
.spy
.chan
)
383 ast_channel_whisper_stop(csth
.spy
.chan
);
385 if (ast_test_flag(flags
, OPTION_PRIVATE
))
386 ast_channel_stop_silence_generator(chan
, silgen
);
388 ast_deactivate_generator(chan
);
390 csth
.spy
.status
= CHANSPY_DONE
;
392 /* If a channel still exists on our spy structure then we need to remove ourselves */
394 ast_channel_lock(csth
.spy
.chan
);
395 ast_channel_spy_remove(csth
.spy
.chan
, &csth
.spy
);
396 ast_channel_unlock(csth
.spy
.chan
);
398 ast_channel_spy_free(&csth
.spy
);
400 if (option_verbose
>= 2)
401 ast_verbose(VERBOSE_PREFIX_2
"Done Spying on channel %s\n", name
);
406 static struct ast_channel
*next_channel(const struct ast_channel
*last
, const char *spec
,
407 const char *exten
, const char *context
)
409 struct ast_channel
*this;
413 this = ast_walk_channel_by_name_prefix_locked(last
, spec
, strlen(spec
));
415 this = ast_walk_channel_by_exten_locked(last
, exten
, context
);
417 this = ast_channel_walk_locked(last
);
420 ast_channel_unlock(this);
421 if (!strncmp(this->name
, "Zap/pseudo", 10))
428 static int common_exec(struct ast_channel
*chan
, const struct ast_flags
*flags
,
429 int volfactor
, const int fd
, const char *mygroup
, const char *spec
,
430 const char *exten
, const char *context
)
432 struct ast_channel
*peer
, *prev
, *next
;
433 char nameprefix
[AST_NAME_STRLEN
];
434 char peer_name
[AST_NAME_STRLEN
+ 5];
435 signed char zero_volume
= 0;
441 if (chan
->_state
!= AST_STATE_UP
)
444 ast_set_flag(chan
, AST_FLAG_SPYING
); /* so nobody can spy on us while we are spying */
449 if (!ast_test_flag(flags
, OPTION_QUIET
)) {
450 res
= ast_streamfile(chan
, "beep", chan
->language
);
452 res
= ast_waitstream(chan
, "");
454 ast_clear_flag(chan
, AST_FLAG_SPYING
);
459 res
= ast_waitfordigit(chan
, waitms
);
461 ast_clear_flag(chan
, AST_FLAG_SPYING
);
465 /* reset for the next loop around, unless overridden later */
467 peer
= prev
= next
= NULL
;
469 for (peer
= next_channel(peer
, spec
, exten
, context
);
471 prev
= peer
, peer
= next
? next
: next_channel(peer
, spec
, exten
, context
), next
= NULL
) {
486 if (ast_test_flag(flags
, OPTION_BRIDGED
) && !ast_bridged_channel(peer
))
489 if (ast_check_hangup(peer
) || ast_test_flag(peer
, AST_FLAG_SPYING
))
493 if ((group
= pbx_builtin_getvar_helper(peer
, "SPYGROUP"))) {
494 dup_group
= ast_strdupa(group
);
495 num_groups
= ast_app_separate_args(dup_group
, ':', groups
,
496 sizeof(groups
) / sizeof(groups
[0]));
499 for (x
= 0; x
< num_groups
; x
++) {
500 if (!strcmp(mygroup
, groups
[x
])) {
510 strcpy(peer_name
, "spy-");
511 strncat(peer_name
, peer
->name
, AST_NAME_STRLEN
);
512 ptr
= strchr(peer_name
, '/');
515 for (s
= peer_name
; s
< ptr
; s
++)
518 if (!ast_test_flag(flags
, OPTION_QUIET
)) {
519 if (ast_fileexists(peer_name
, NULL
, NULL
) != -1) {
520 res
= ast_streamfile(chan
, peer_name
, chan
->language
);
522 res
= ast_waitstream(chan
, "");
526 res
= ast_say_character_str(chan
, peer_name
, "", chan
->language
);
527 if ((num
= atoi(ptr
)))
528 ast_say_digits(chan
, atoi(ptr
), "", chan
->language
);
532 res
= channel_spy(chan
, peer
, &volfactor
, fd
, flags
);
536 } else if (res
> 1 && spec
) {
537 snprintf(nameprefix
, AST_NAME_STRLEN
, "%s/%d", spec
, res
);
538 if ((next
= ast_get_channel_by_name_prefix_locked(nameprefix
, strlen(nameprefix
)))) {
539 ast_channel_unlock(next
);
541 /* stay on this channel */
551 ast_clear_flag(chan
, AST_FLAG_SPYING
);
553 ast_channel_setoption(chan
, AST_OPTION_TXGAIN
, &zero_volume
, sizeof(zero_volume
), 0);
558 static int chanspy_exec(struct ast_channel
*chan
, void *data
)
560 struct ast_module_user
*u
;
561 char *options
= NULL
;
564 char *mygroup
= NULL
;
565 char *recbase
= NULL
;
567 struct ast_flags flags
;
573 data
= ast_strdupa(data
);
575 u
= ast_module_user_add(chan
);
577 if ((argc
= ast_app_separate_args(data
, '|', argv
, sizeof(argv
) / sizeof(argv
[0])))) {
582 if (ast_strlen_zero(spec
) || !strcmp(spec
, "all"))
587 char *opts
[OPT_ARG_ARRAY_SIZE
];
589 ast_app_parse_options(spy_opts
, &flags
, opts
, options
);
590 if (ast_test_flag(&flags
, OPTION_GROUP
))
591 mygroup
= opts
[OPT_ARG_GROUP
];
593 if (ast_test_flag(&flags
, OPTION_RECORD
) &&
594 !(recbase
= opts
[OPT_ARG_RECORD
]))
597 if (ast_test_flag(&flags
, OPTION_VOLUME
) && opts
[OPT_ARG_VOLUME
]) {
600 if ((sscanf(opts
[OPT_ARG_VOLUME
], "%d", &vol
) != 1) || (vol
> 4) || (vol
< -4))
601 ast_log(LOG_NOTICE
, "Volume factor must be a number between -4 and 4\n");
606 if (ast_test_flag(&flags
, OPTION_PRIVATE
))
607 ast_set_flag(&flags
, OPTION_WHISPER
);
609 ast_clear_flag(&flags
, AST_FLAGS_ALL
);
611 oldwf
= chan
->writeformat
;
612 if (ast_set_write_format(chan
, AST_FORMAT_SLINEAR
) < 0) {
613 ast_log(LOG_ERROR
, "Could Not Set Write Format.\n");
614 ast_module_user_remove(u
);
621 snprintf(filename
, sizeof(filename
), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR
, recbase
, (int) time(NULL
));
622 if ((fd
= open(filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0644)) <= 0) {
623 ast_log(LOG_WARNING
, "Cannot open '%s' for recording\n", filename
);
628 res
= common_exec(chan
, &flags
, volfactor
, fd
, mygroup
, spec
, NULL
, NULL
);
633 if (oldwf
&& ast_set_write_format(chan
, oldwf
) < 0)
634 ast_log(LOG_ERROR
, "Could Not Set Write Format.\n");
636 ast_module_user_remove(u
);
641 static int extenspy_exec(struct ast_channel
*chan
, void *data
)
643 struct ast_module_user
*u
;
644 char *options
= NULL
;
646 char *context
= NULL
;
648 char *mygroup
= NULL
;
649 char *recbase
= NULL
;
651 struct ast_flags flags
;
657 data
= ast_strdupa(data
);
659 u
= ast_module_user_add(chan
);
661 if ((argc
= ast_app_separate_args(data
, '|', argv
, sizeof(argv
) / sizeof(argv
[0])))) {
663 if (!ast_strlen_zero(argv
[0]))
664 exten
= strsep(&context
, "@");
665 if (ast_strlen_zero(context
))
666 context
= ast_strdupa(chan
->context
);
672 char *opts
[OPT_ARG_ARRAY_SIZE
];
674 ast_app_parse_options(spy_opts
, &flags
, opts
, options
);
675 if (ast_test_flag(&flags
, OPTION_GROUP
))
676 mygroup
= opts
[OPT_ARG_GROUP
];
678 if (ast_test_flag(&flags
, OPTION_RECORD
) &&
679 !(recbase
= opts
[OPT_ARG_RECORD
]))
682 if (ast_test_flag(&flags
, OPTION_VOLUME
) && opts
[OPT_ARG_VOLUME
]) {
685 if ((sscanf(opts
[OPT_ARG_VOLUME
], "%d", &vol
) != 1) || (vol
> 4) || (vol
< -4))
686 ast_log(LOG_NOTICE
, "Volume factor must be a number between -4 and 4\n");
691 if (ast_test_flag(&flags
, OPTION_PRIVATE
))
692 ast_set_flag(&flags
, OPTION_WHISPER
);
694 ast_clear_flag(&flags
, AST_FLAGS_ALL
);
696 oldwf
= chan
->writeformat
;
697 if (ast_set_write_format(chan
, AST_FORMAT_SLINEAR
) < 0) {
698 ast_log(LOG_ERROR
, "Could Not Set Write Format.\n");
699 ast_module_user_remove(u
);
706 snprintf(filename
, sizeof(filename
), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR
, recbase
, (int) time(NULL
));
707 if ((fd
= open(filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, 0644)) <= 0) {
708 ast_log(LOG_WARNING
, "Cannot open '%s' for recording\n", filename
);
713 res
= common_exec(chan
, &flags
, volfactor
, fd
, mygroup
, NULL
, exten
, context
);
718 if (oldwf
&& ast_set_write_format(chan
, oldwf
) < 0)
719 ast_log(LOG_ERROR
, "Could Not Set Write Format.\n");
721 ast_module_user_remove(u
);
726 static int unload_module(void)
730 res
|= ast_unregister_application(app_chan
);
731 res
|= ast_unregister_application(app_ext
);
733 ast_module_user_hangup_all();
738 static int load_module(void)
742 res
|= ast_register_application(app_chan
, chanspy_exec
, tdesc
, desc_chan
);
743 res
|= ast_register_application(app_ext
, extenspy_exec
, tdesc
, desc_ext
);
748 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Listen to the audio of an active channel");