Add a function, CHANNELS(), which retrieves a list of all active channels.
[asterisk-bristuff.git] / res / res_monitor.c
blobf3be16f7a5c0d537b7c9f4bd4d5e0c32923b2de9
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*! \file
21 * \brief PBX channel monitoring
23 * \author Mark Spencer <markster@digium.com>
26 #include "asterisk.h"
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include <sys/stat.h>
31 #include <libgen.h>
33 #include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
34 #include "asterisk/lock.h"
35 #include "asterisk/channel.h"
36 #include "asterisk/file.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/module.h"
39 #include "asterisk/manager.h"
40 #include "asterisk/cli.h"
41 #include "asterisk/monitor.h"
42 #include "asterisk/app.h"
43 #include "asterisk/utils.h"
44 #include "asterisk/config.h"
45 #include "asterisk/options.h"
47 AST_MUTEX_DEFINE_STATIC(monitorlock);
49 #define LOCK_IF_NEEDED(lock, needed) do { \
50 if (needed) \
51 ast_channel_lock(lock); \
52 } while(0)
54 #define UNLOCK_IF_NEEDED(lock, needed) do { \
55 if (needed) \
56 ast_channel_unlock(lock); \
57 } while (0)
59 static unsigned long seq = 0;
61 static char *monitor_synopsis = "Monitor a channel";
63 static char *monitor_descrip = " Monitor([file_format[:urlbase],[fname_base],[options]]):\n"
64 "Used to start monitoring a channel. The channel's input and output\n"
65 "voice packets are logged to files until the channel hangs up or\n"
66 "monitoring is stopped by the StopMonitor application.\n"
67 " file_format optional, if not set, defaults to \"wav\"\n"
68 " fname_base if set, changes the filename used to the one specified.\n"
69 " options:\n"
70 " m - when the recording ends mix the two leg files into one and\n"
71 " delete the two leg files. If the variable MONITOR_EXEC is set, the\n"
72 " application referenced in it will be executed instead of\n"
73 #ifdef HAVE_SOXMIX
74 " soxmix and the raw leg files will NOT be deleted automatically.\n"
75 " soxmix or MONITOR_EXEC is handed 3 arguments, the two leg files\n"
76 #else
77 " sox and the raw leg files will NOT be deleted automatically.\n"
78 " sox or MONITOR_EXEC is handed 3 arguments, the two leg files\n"
79 #endif
80 " and a target mixed file name which is the same as the leg file names\n"
81 " only without the in/out designator.\n"
82 " If MONITOR_EXEC_ARGS is set, the contents will be passed on as\n"
83 " additional arguments to MONITOR_EXEC\n"
84 " Both MONITOR_EXEC and the Mix flag can be set from the\n"
85 " administrator interface\n"
86 "\n"
87 " b - Don't begin recording unless a call is bridged to another channel\n"
88 " i - Skip recording of input stream (disables m option)\n"
89 " o - Skip recording of output stream (disables m option)\n"
90 "\nReturns -1 if monitor files can't be opened or if the channel is already\n"
91 "monitored, otherwise 0.\n"
94 static char *stopmonitor_synopsis = "Stop monitoring a channel";
96 static char *stopmonitor_descrip = " StopMonitor():\n"
97 "Stops monitoring a channel. Has no effect if the channel is not monitored\n";
99 static char *changemonitor_synopsis = "Change monitoring filename of a channel";
101 static char *changemonitor_descrip = " ChangeMonitor(filename_base):\n"
102 "Changes monitoring filename of a channel. Has no effect if the channel is not monitored.\n"
103 "The argument is the new filename base to use for monitoring this channel.\n";
105 static char *pausemonitor_synopsis = "Pause monitoring of a channel";
107 static char *pausemonitor_descrip = " PauseMonitor():\n"
108 "Pauses monitoring of a channel until it is re-enabled by a call to UnpauseMonitor.\n";
110 static char *unpausemonitor_synopsis = "Unpause monitoring of a channel";
112 static char *unpausemonitor_descrip = " UnpauseMonitor():\n"
113 "Unpauses monitoring of a channel on which monitoring had\n"
114 "previously been paused with PauseMonitor.\n";
116 /*!
117 * \brief Change state of monitored channel
118 * \param chan
119 * \param state monitor state
120 * \retval 0 on success.
121 * \retval -1 on failure.
123 static int ast_monitor_set_state(struct ast_channel *chan, int state)
125 LOCK_IF_NEEDED(chan, 1);
126 if (!chan->monitor) {
127 UNLOCK_IF_NEEDED(chan, 1);
128 return -1;
130 chan->monitor->state = state;
131 UNLOCK_IF_NEEDED(chan, 1);
132 return 0;
135 /*! \brief Start monitoring a channel
136 * \param chan ast_channel struct to record
137 * \param format_spec file format to use for recording
138 * \param fname_base filename base to record to
139 * \param need_lock whether to lock the channel mutex
140 * \param stream_action whether to record the input and/or output streams. X_REC_IN | X_REC_OUT is most often used
141 * Creates the file to record, if no format is specified it assumes WAV
142 * It also sets channel variable __MONITORED=yes
143 * \retval 0 on success
144 * \retval -1 on failure
146 int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
147 const char *fname_base, int need_lock, int stream_action)
149 int res = 0;
151 LOCK_IF_NEEDED(chan, need_lock);
153 if (!(chan->monitor)) {
154 struct ast_channel_monitor *monitor;
155 char *channel_name, *p;
157 /* Create monitoring directory if needed */
158 ast_mkdir(ast_config_AST_MONITOR_DIR, 0777);
160 if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
161 UNLOCK_IF_NEEDED(chan, need_lock);
162 return -1;
165 /* Determine file names */
166 if (!ast_strlen_zero(fname_base)) {
167 int directory = strchr(fname_base, '/') ? 1 : 0;
168 const char *absolute = *fname_base == '/' ? "" : "/";
169 /* try creating the directory just in case it doesn't exist */
170 if (directory) {
171 char *name = ast_strdupa(fname_base);
172 ast_mkdir(dirname(name), 0777);
174 snprintf(monitor->read_filename, FILENAME_MAX, "%s%s%s-in",
175 directory ? "" : ast_config_AST_MONITOR_DIR, absolute, fname_base);
176 snprintf(monitor->write_filename, FILENAME_MAX, "%s%s%s-out",
177 directory ? "" : ast_config_AST_MONITOR_DIR, absolute, fname_base);
178 ast_copy_string(monitor->filename_base, fname_base, sizeof(monitor->filename_base));
179 } else {
180 ast_mutex_lock(&monitorlock);
181 snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
182 ast_config_AST_MONITOR_DIR, seq);
183 snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
184 ast_config_AST_MONITOR_DIR, seq);
185 seq++;
186 ast_mutex_unlock(&monitorlock);
188 channel_name = ast_strdupa(chan->name);
189 while ((p = strchr(channel_name, '/'))) {
190 *p = '-';
192 snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
193 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
194 monitor->filename_changed = 1;
197 monitor->stop = ast_monitor_stop;
199 /* Determine file format */
200 if (!ast_strlen_zero(format_spec)) {
201 monitor->format = ast_strdup(format_spec);
202 } else {
203 monitor->format = ast_strdup("wav");
206 /* open files */
207 if (stream_action & X_REC_IN) {
208 if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0)
209 ast_filedelete(monitor->read_filename, NULL);
210 if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
211 monitor->format, NULL,
212 O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
213 ast_log(LOG_WARNING, "Could not create file %s\n",
214 monitor->read_filename);
215 ast_free(monitor);
216 UNLOCK_IF_NEEDED(chan, need_lock);
217 return -1;
219 } else
220 monitor->read_stream = NULL;
222 if (stream_action & X_REC_OUT) {
223 if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
224 ast_filedelete(monitor->write_filename, NULL);
226 if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
227 monitor->format, NULL,
228 O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
229 ast_log(LOG_WARNING, "Could not create file %s\n",
230 monitor->write_filename);
231 ast_closestream(monitor->read_stream);
232 ast_free(monitor);
233 UNLOCK_IF_NEEDED(chan, need_lock);
234 return -1;
236 } else
237 monitor->write_stream = NULL;
239 chan->monitor = monitor;
240 ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
241 /* so we know this call has been monitored in case we need to bill for it or something */
242 pbx_builtin_setvar_helper(chan, "__MONITORED","true");
244 manager_event(EVENT_FLAG_CALL, "MonitorStart",
245 "Channel: %s\r\n"
246 "Uniqueid: %s\r\n",
247 chan->name,
248 chan->uniqueid
250 } else {
251 ast_debug(1,"Cannot start monitoring %s, already monitored\n", chan->name);
252 res = -1;
255 UNLOCK_IF_NEEDED(chan, need_lock);
257 return res;
261 * \brief Get audio format.
262 * \param format recording format.
263 * The file format extensions that Asterisk uses are not all the same as that
264 * which soxmix expects. This function ensures that the format used as the
265 * extension on the filename is something soxmix will understand.
267 static const char *get_soxmix_format(const char *format)
269 const char *res = format;
271 if (!strcasecmp(format,"ulaw"))
272 res = "ul";
273 if (!strcasecmp(format,"alaw"))
274 res = "al";
276 return res;
279 /*!
280 * \brief Stop monitoring channel
281 * \param chan
282 * \param need_lock
283 * Stop the recording, close any open streams, mix in/out channels if required
284 * \return Always 0
286 int ast_monitor_stop(struct ast_channel *chan, int need_lock)
288 int delfiles = 0;
290 LOCK_IF_NEEDED(chan, need_lock);
292 if (chan->monitor) {
293 char filename[ FILENAME_MAX ];
295 if (chan->monitor->read_stream) {
296 ast_closestream(chan->monitor->read_stream);
298 if (chan->monitor->write_stream) {
299 ast_closestream(chan->monitor->write_stream);
302 if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
303 if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
304 snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
305 if (ast_fileexists(filename, NULL, NULL) > 0) {
306 ast_filedelete(filename, NULL);
308 ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
309 } else {
310 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
313 if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
314 snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
315 if (ast_fileexists(filename, NULL, NULL) > 0) {
316 ast_filedelete(filename, NULL);
318 ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
319 } else {
320 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
324 if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
325 char tmp[1024];
326 char tmp2[1024];
327 const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
328 char *name = chan->monitor->filename_base;
329 int directory = strchr(name, '/') ? 1 : 0;
330 const char *dir = directory ? "" : ast_config_AST_MONITOR_DIR;
331 const char *execute, *execute_args;
332 const char *absolute = *name == '/' ? "" : "/";
334 /* Set the execute application */
335 execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
336 if (ast_strlen_zero(execute)) {
337 #ifdef HAVE_SOXMIX
338 execute = "nice -n 19 soxmix";
339 #else
340 execute = "nice -n 19 sox -m";
341 #endif
342 format = get_soxmix_format(format);
343 delfiles = 1;
345 execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
346 if (ast_strlen_zero(execute_args)) {
347 execute_args = "";
350 snprintf(tmp, sizeof(tmp), "%s \"%s%s%s-in.%s\" \"%s%s%s-out.%s\" \"%s%s%s.%s\" %s &", execute, dir, absolute, name, format, dir, absolute, name, format, dir, absolute, name, format,execute_args);
351 if (delfiles) {
352 snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s%s%s-\"* ) &",tmp, dir, absolute, name); /* remove legs when done mixing */
353 ast_copy_string(tmp, tmp2, sizeof(tmp));
355 ast_debug(1,"monitor executing %s\n",tmp);
356 if (ast_safe_system(tmp) == -1)
357 ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
360 ast_free(chan->monitor->format);
361 ast_free(chan->monitor);
362 chan->monitor = NULL;
364 manager_event(EVENT_FLAG_CALL, "MonitorStop",
365 "Channel: %s\r\n"
366 "Uniqueid: %s\r\n",
367 chan->name,
368 chan->uniqueid
372 UNLOCK_IF_NEEDED(chan, need_lock);
374 return 0;
378 /*! \brief Pause monitoring of channel */
379 int ast_monitor_pause(struct ast_channel *chan)
381 return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
384 /*! \brief Unpause monitoring of channel */
385 int ast_monitor_unpause(struct ast_channel *chan)
387 return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
390 /*! \brief Wrapper for ast_monitor_pause */
391 static int pause_monitor_exec(struct ast_channel *chan, void *data)
393 return ast_monitor_pause(chan);
396 /*! \brief Wrapper for ast_monitor_unpause */
397 static int unpause_monitor_exec(struct ast_channel *chan, void *data)
399 return ast_monitor_unpause(chan);
402 /*!
403 * \brief Change monitored filename of channel
404 * \param chan
405 * \param fname_base new filename
406 * \param need_lock
407 * \retval 0 on success.
408 * \retval -1 on failure.
410 int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, int need_lock)
412 if (ast_strlen_zero(fname_base)) {
413 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name);
414 return -1;
417 LOCK_IF_NEEDED(chan, need_lock);
419 if (chan->monitor) {
420 int directory = strchr(fname_base, '/') ? 1 : 0;
421 const char *absolute = *fname_base == '/' ? "" : "/";
422 char tmpstring[sizeof(chan->monitor->filename_base)] = "";
424 /* before continuing, see if we're trying to rename the file to itself... */
425 snprintf(tmpstring, sizeof(tmpstring), "%s%s%s", directory ? "" : ast_config_AST_MONITOR_DIR, absolute, fname_base);
426 if (!strcmp(tmpstring, chan->monitor->filename_base)) {
427 if (option_debug > 2)
428 ast_log(LOG_DEBUG, "No need to rename monitor filename to itself\n");
429 UNLOCK_IF_NEEDED(chan, need_lock);
430 return 0;
433 /* try creating the directory just in case it doesn't exist */
434 if (directory) {
435 char *name = ast_strdupa(fname_base);
436 ast_mkdir(dirname(name), 0777);
439 ast_copy_string(chan->monitor->filename_base, tmpstring, sizeof(chan->monitor->filename_base));
440 chan->monitor->filename_changed = 1;
441 } else {
442 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base);
445 UNLOCK_IF_NEEDED(chan, need_lock);
447 return 0;
452 * \brief Start monitor
453 * \param chan
454 * \param data arguments passed fname|options
455 * \retval 0 on success.
456 * \retval -1 on failure.
458 static int start_monitor_exec(struct ast_channel *chan, void *data)
460 char *arg = NULL;
461 char *options = NULL;
462 char *delay = NULL;
463 char *urlprefix = NULL;
464 char tmp[256];
465 int stream_action = X_REC_IN | X_REC_OUT;
466 int joinfiles = 0;
467 int waitforbridge = 0;
468 int res = 0;
469 char *parse;
470 AST_DECLARE_APP_ARGS(args,
471 AST_APP_ARG(format);
472 AST_APP_ARG(fname_base);
473 AST_APP_ARG(options);
476 /* Parse arguments. */
477 if (ast_strlen_zero((char*)data)) {
478 ast_log(LOG_ERROR, "Monitor requires an argument\n");
479 return 0;
482 parse = ast_strdupa((char*)data);
483 AST_STANDARD_APP_ARGS(args, parse);
485 if (!ast_strlen_zero(args.options)) {
486 if (strchr(args.options, 'm'))
487 stream_action |= X_JOIN;
488 if (strchr(args.options, 'b'))
489 waitforbridge = 1;
490 if (strchr(args.options, 'i'))
491 stream_action &= ~X_REC_IN;
492 if (strchr(args.options, 'o'))
493 stream_action &= ~X_REC_OUT;
496 arg = strchr(args.format, ':');
497 if (arg) {
498 *arg++ = 0;
499 urlprefix = arg;
502 if (urlprefix) {
503 snprintf(tmp, sizeof(tmp), "%s/%s.%s", urlprefix, args.fname_base,
504 ((strcmp(args.format, "gsm")) ? "wav" : "gsm"));
505 if (!chan->cdr && !(chan->cdr = ast_cdr_alloc()))
506 return -1;
507 ast_cdr_setuserfield(chan, tmp);
509 if (waitforbridge) {
510 /* We must remove the "b" option if listed. In principle none of
511 the following could give NULL results, but we check just to
512 be pedantic. Reconstructing with checks for 'm' option does not
513 work if we end up adding more options than 'm' in the future. */
514 delay = ast_strdupa(data);
515 options = strrchr(delay, ',');
516 if (options) {
517 arg = strchr(options, 'b');
518 if (arg) {
519 *arg = 'X';
520 pbx_builtin_setvar_helper(chan,"AUTO_MONITOR", delay);
523 return 0;
526 res = ast_monitor_start(chan, args.format, args.fname_base, 1, stream_action);
527 if (res < 0)
528 res = ast_monitor_change_fname(chan, args.fname_base, 1);
530 if (stream_action & X_JOIN) {
531 if ((stream_action & X_REC_IN) && (stream_action & X_REC_OUT))
532 joinfiles = 1;
533 else
534 ast_log(LOG_WARNING, "Won't mix streams unless both input and output streams are recorded\n");
536 ast_monitor_setjoinfiles(chan, joinfiles);
538 return res;
541 /*! \brief Wrapper function \see ast_monitor_stop */
542 static int stop_monitor_exec(struct ast_channel *chan, void *data)
544 return ast_monitor_stop(chan, 1);
547 /*! \brief Wrapper function \see ast_monitor_change_fname */
548 static int change_monitor_exec(struct ast_channel *chan, void *data)
550 return ast_monitor_change_fname(chan, (const char*)data, 1);
553 static char start_monitor_action_help[] =
554 "Description: The 'Monitor' action may be used to record the audio on a\n"
555 " specified channel. The following parameters may be used to control\n"
556 " this:\n"
557 " Channel - Required. Used to specify the channel to record.\n"
558 " File - Optional. Is the name of the file created in the\n"
559 " monitor spool directory. Defaults to the same name\n"
560 " as the channel (with slashes replaced with dashes).\n"
561 " Format - Optional. Is the audio recording format. Defaults\n"
562 " to \"wav\".\n"
563 " Mix - Optional. Boolean parameter as to whether to mix\n"
564 " the input and output channels together after the\n"
565 " recording is finished.\n";
567 /*! \brief Start monitoring a channel by manager connection */
568 static int start_monitor_action(struct mansession *s, const struct message *m)
570 struct ast_channel *c = NULL;
571 const char *name = astman_get_header(m, "Channel");
572 const char *fname = astman_get_header(m, "File");
573 const char *format = astman_get_header(m, "Format");
574 const char *mix = astman_get_header(m, "Mix");
575 char *d;
577 if (ast_strlen_zero(name)) {
578 astman_send_error(s, m, "No channel specified");
579 return 0;
581 c = ast_get_channel_by_name_locked(name);
582 if (!c) {
583 astman_send_error(s, m, "No such channel");
584 return 0;
587 if (ast_strlen_zero(fname)) {
588 /* No filename base specified, default to channel name as per CLI */
589 if (!(fname = ast_strdup(c->name))) {
590 astman_send_error(s, m, "Could not start monitoring channel");
591 ast_channel_unlock(c);
592 return 0;
594 /* Channels have the format technology/channel_name - have to replace that / */
595 if ((d = strchr(fname, '/')))
596 *d = '-';
599 if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT)) {
600 if (ast_monitor_change_fname(c, fname, 1)) {
601 astman_send_error(s, m, "Could not start monitoring channel");
602 ast_channel_unlock(c);
603 return 0;
607 if (ast_true(mix)) {
608 ast_monitor_setjoinfiles(c, 1);
611 ast_channel_unlock(c);
612 astman_send_ack(s, m, "Started monitoring channel");
613 return 0;
616 static char stop_monitor_action_help[] =
617 "Description: The 'StopMonitor' action may be used to end a previously\n"
618 " started 'Monitor' action. The only parameter is 'Channel', the name\n"
619 " of the channel monitored.\n";
621 /*! \brief Stop monitoring a channel by manager connection */
622 static int stop_monitor_action(struct mansession *s, const struct message *m)
624 struct ast_channel *c = NULL;
625 const char *name = astman_get_header(m, "Channel");
626 int res;
627 if (ast_strlen_zero(name)) {
628 astman_send_error(s, m, "No channel specified");
629 return 0;
631 c = ast_get_channel_by_name_locked(name);
632 if (!c) {
633 astman_send_error(s, m, "No such channel");
634 return 0;
636 res = ast_monitor_stop(c, 1);
637 ast_channel_unlock(c);
638 if (res) {
639 astman_send_error(s, m, "Could not stop monitoring channel");
640 return 0;
642 astman_send_ack(s, m, "Stopped monitoring channel");
643 return 0;
646 static char change_monitor_action_help[] =
647 "Description: The 'ChangeMonitor' action may be used to change the file\n"
648 " started by a previous 'Monitor' action. The following parameters may\n"
649 " be used to control this:\n"
650 " Channel - Required. Used to specify the channel to record.\n"
651 " File - Required. Is the new name of the file created in the\n"
652 " monitor spool directory.\n";
654 /*! \brief Change filename of a monitored channel by manager connection */
655 static int change_monitor_action(struct mansession *s, const struct message *m)
657 struct ast_channel *c = NULL;
658 const char *name = astman_get_header(m, "Channel");
659 const char *fname = astman_get_header(m, "File");
660 if (ast_strlen_zero(name)) {
661 astman_send_error(s, m, "No channel specified");
662 return 0;
664 if (ast_strlen_zero(fname)) {
665 astman_send_error(s, m, "No filename specified");
666 return 0;
668 c = ast_get_channel_by_name_locked(name);
669 if (!c) {
670 astman_send_error(s, m, "No such channel");
671 return 0;
673 if (ast_monitor_change_fname(c, fname, 1)) {
674 astman_send_error(s, m, "Could not change monitored filename of channel");
675 ast_channel_unlock(c);
676 return 0;
678 ast_channel_unlock(c);
679 astman_send_ack(s, m, "Changed monitor filename");
680 return 0;
683 void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
685 if (chan->monitor)
686 chan->monitor->joinfiles = turnon;
689 enum MONITOR_PAUSING_ACTION
691 MONITOR_ACTION_PAUSE,
692 MONITOR_ACTION_UNPAUSE
695 static int do_pause_or_unpause(struct mansession *s, const struct message *m, int action)
697 struct ast_channel *c = NULL;
698 const char *name = astman_get_header(m, "Channel");
700 if (ast_strlen_zero(name)) {
701 astman_send_error(s, m, "No channel specified");
702 return -1;
705 c = ast_get_channel_by_name_locked(name);
706 if (!c) {
707 astman_send_error(s, m, "No such channel");
708 return -1;
711 if (action == MONITOR_ACTION_PAUSE)
712 ast_monitor_pause(c);
713 else
714 ast_monitor_unpause(c);
716 ast_channel_unlock(c);
717 astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel"));
718 return 0;
721 static char pause_monitor_action_help[] =
722 "Description: The 'PauseMonitor' action may be used to temporarily stop the\n"
723 " recording of a channel. The following parameters may\n"
724 " be used to control this:\n"
725 " Channel - Required. Used to specify the channel to record.\n";
727 static int pause_monitor_action(struct mansession *s, const struct message *m)
729 return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
732 static char unpause_monitor_action_help[] =
733 "Description: The 'UnpauseMonitor' action may be used to re-enable recording\n"
734 " of a channel after calling PauseMonitor. The following parameters may\n"
735 " be used to control this:\n"
736 " Channel - Required. Used to specify the channel to record.\n";
738 static int unpause_monitor_action(struct mansession *s, const struct message *m)
740 return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
744 static int load_module(void)
746 ast_register_application("Monitor", start_monitor_exec, monitor_synopsis, monitor_descrip);
747 ast_register_application("StopMonitor", stop_monitor_exec, stopmonitor_synopsis, stopmonitor_descrip);
748 ast_register_application("ChangeMonitor", change_monitor_exec, changemonitor_synopsis, changemonitor_descrip);
749 ast_register_application("PauseMonitor", pause_monitor_exec, pausemonitor_synopsis, pausemonitor_descrip);
750 ast_register_application("UnpauseMonitor", unpause_monitor_exec, unpausemonitor_synopsis, unpausemonitor_descrip);
751 ast_manager_register2("Monitor", EVENT_FLAG_CALL, start_monitor_action, monitor_synopsis, start_monitor_action_help);
752 ast_manager_register2("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action, stopmonitor_synopsis, stop_monitor_action_help);
753 ast_manager_register2("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action, changemonitor_synopsis, change_monitor_action_help);
754 ast_manager_register2("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action, pausemonitor_synopsis, pause_monitor_action_help);
755 ast_manager_register2("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action, unpausemonitor_synopsis, unpause_monitor_action_help);
757 return AST_MODULE_LOAD_SUCCESS;
760 static int unload_module(void)
762 ast_unregister_application("Monitor");
763 ast_unregister_application("StopMonitor");
764 ast_unregister_application("ChangeMonitor");
765 ast_unregister_application("PauseMonitor");
766 ast_unregister_application("UnpauseMonitor");
767 ast_manager_unregister("Monitor");
768 ast_manager_unregister("StopMonitor");
769 ast_manager_unregister("ChangeMonitor");
770 ast_manager_unregister("PauseMonitor");
771 ast_manager_unregister("UnpauseMonitor");
773 return 0;
776 /* usecount semantics need to be defined */
777 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Monitoring Resource",
778 .load = load_module,
779 .unload = unload_module,