Fri Sep 25 19:28:15 2009

Asterisk developer's documentation


res_monitor.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief PBX channel monitoring
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  */
00025  
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 94122 $")
00029 
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <errno.h>
00033 #include <string.h>
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <libgen.h>
00037 
00038 #include "asterisk/lock.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/logger.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/pbx.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/manager.h"
00045 #include "asterisk/cli.h"
00046 #include "asterisk/monitor.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/utils.h"
00049 #include "asterisk/config.h"
00050 
00051 AST_MUTEX_DEFINE_STATIC(monitorlock);
00052 
00053 #define LOCK_IF_NEEDED(lock, needed) do { \
00054    if (needed) \
00055       ast_channel_lock(lock); \
00056    } while(0)
00057 
00058 #define UNLOCK_IF_NEEDED(lock, needed) do { \
00059    if (needed) \
00060       ast_channel_unlock(lock); \
00061    } while (0)
00062 
00063 static unsigned long seq = 0;
00064 
00065 static char *monitor_synopsis = "Monitor a channel";
00066 
00067 static char *monitor_descrip = "Monitor([file_format[:urlbase]|[fname_base]|[options]]):\n"
00068 "Used to start monitoring a channel. The channel's input and output\n"
00069 "voice packets are logged to files until the channel hangs up or\n"
00070 "monitoring is stopped by the StopMonitor application.\n"
00071 "  file_format    optional, if not set, defaults to \"wav\"\n"
00072 "  fname_base     if set, changes the filename used to the one specified.\n"
00073 "  options:\n"
00074 "    m   - when the recording ends mix the two leg files into one and\n"
00075 "          delete the two leg files.  If the variable MONITOR_EXEC is set, the\n"
00076 "          application referenced in it will be executed instead of\n"
00077 #ifdef HAVE_SOXMIX
00078 "          soxmix and the raw leg files will NOT be deleted automatically.\n"
00079 "          soxmix or MONITOR_EXEC is handed 3 arguments, the two leg files\n"
00080 #else
00081 "          sox and the raw leg files will NOT be deleted automatically.\n"
00082 "          sox or MONITOR_EXEC is handed 3 arguments, the two leg files\n"
00083 #endif
00084 "          and a target mixed file name which is the same as the leg file names\n"
00085 "          only without the in/out designator.\n"
00086 "          If MONITOR_EXEC_ARGS is set, the contents will be passed on as\n"
00087 "          additional arguements to MONITOR_EXEC\n"
00088 "          Both MONITOR_EXEC and the Mix flag can be set from the\n"
00089 "          administrator interface\n"
00090 "\n"
00091 "    b   - Don't begin recording unless a call is bridged to another channel\n"
00092 "\nReturns -1 if monitor files can't be opened or if the channel is already\n"
00093 "monitored, otherwise 0.\n"
00094 ;
00095 
00096 static char *stopmonitor_synopsis = "Stop monitoring a channel";
00097 
00098 static char *stopmonitor_descrip = "StopMonitor\n"
00099    "Stops monitoring a channel. Has no effect if the channel is not monitored\n";
00100 
00101 static char *changemonitor_synopsis = "Change monitoring filename of a channel";
00102 
00103 static char *changemonitor_descrip = "ChangeMonitor(filename_base)\n"
00104    "Changes monitoring filename of a channel. Has no effect if the channel is not monitored\n"
00105    "The argument is the new filename base to use for monitoring this channel.\n";
00106 
00107 static char *pausemonitor_synopsis = "Pause monitoring of a channel";
00108 
00109 static char *pausemonitor_descrip = "PauseMonitor\n"
00110    "Pauses monitoring of a channel until it is re-enabled by a call to UnpauseMonitor.\n";
00111 
00112 static char *unpausemonitor_synopsis = "Unpause monitoring of a channel";
00113 
00114 static char *unpausemonitor_descrip = "UnpauseMonitor\n"
00115    "Unpauses monitoring of a channel on which monitoring had\n"
00116    "previously been paused with PauseMonitor.\n";
00117 
00118 static int ast_monitor_set_state(struct ast_channel *chan, int state)
00119 {
00120    LOCK_IF_NEEDED(chan, 1);
00121    if (!chan->monitor) {
00122       UNLOCK_IF_NEEDED(chan, 1);
00123       return -1;
00124    }
00125    chan->monitor->state = state;
00126    UNLOCK_IF_NEEDED(chan, 1);
00127    return 0;
00128 }
00129 
00130 /* Start monitoring a channel */
00131 int ast_monitor_start(  struct ast_channel *chan, const char *format_spec,
00132       const char *fname_base, const char *target_url, const char *target_script, int need_lock)
00133 {
00134    int res = 0;
00135    char tmp[256];
00136 
00137    LOCK_IF_NEEDED(chan, need_lock);
00138 
00139    if (!(chan->monitor)) {
00140       struct ast_channel_monitor *monitor;
00141       char *channel_name, *p;
00142 
00143       /* Create monitoring directory if needed */
00144       if (mkdir(ast_config_AST_MONITOR_DIR, 0770) < 0) {
00145          if (errno != EEXIST) {
00146             ast_log(LOG_WARNING, "Unable to create audio monitor directory: %s\n",
00147                strerror(errno));
00148          }
00149       }
00150 
00151       if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
00152          UNLOCK_IF_NEEDED(chan, need_lock);
00153          return -1;
00154       }
00155 
00156       if (target_url)
00157           ast_copy_string(monitor->target_url, target_url, sizeof(monitor->target_url));
00158       if (target_script)
00159           ast_copy_string(monitor->target_script, target_script, sizeof(monitor->target_script));
00160 
00161       /* Determine file names */
00162       if (!ast_strlen_zero(fname_base)) {
00163          int directory = strchr(fname_base, '/') ? 1 : 0;
00164          /* try creating the directory just in case it doesn't exist */
00165          if (directory) {
00166             char *name = strdup(fname_base);
00167             snprintf(tmp, sizeof(tmp), "mkdir -p \"%s\"",dirname(name));
00168             free(name);
00169             ast_safe_system(tmp);
00170          }
00171          snprintf(monitor->read_filename, FILENAME_MAX, "%s/%s-in",
00172                   directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
00173          snprintf(monitor->write_filename, FILENAME_MAX, "%s/%s-out",
00174                   directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
00175          ast_copy_string(monitor->filename_base, fname_base, sizeof(monitor->filename_base));
00176       } else {
00177          ast_mutex_lock(&monitorlock);
00178          snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
00179                   ast_config_AST_MONITOR_DIR, seq);
00180          snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
00181                   ast_config_AST_MONITOR_DIR, seq);
00182          seq++;
00183          ast_mutex_unlock(&monitorlock);
00184 
00185          channel_name = ast_strdupa(chan->name);
00186          while ((p = strchr(channel_name, '/'))) {
00187             *p = '-';
00188          }
00189          snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
00190                 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
00191          monitor->filename_changed = 1;
00192       }
00193 
00194       monitor->stop = ast_monitor_stop;
00195 
00196       /* Determine file format */
00197       if (!ast_strlen_zero(format_spec)) {
00198          monitor->format = strdup(format_spec);
00199       } else {
00200          monitor->format = strdup("wav");
00201       }
00202       
00203       /* open files */
00204       if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0) {
00205          ast_filedelete(monitor->read_filename, NULL);
00206       }
00207       if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
00208                   monitor->format, NULL,
00209                   O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
00210          ast_log(LOG_WARNING, "Could not create file %s\n",
00211                   monitor->read_filename);
00212          free(monitor);
00213          UNLOCK_IF_NEEDED(chan, need_lock);
00214          return -1;
00215       }
00216       if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
00217          ast_filedelete(monitor->write_filename, NULL);
00218       }
00219       if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
00220                   monitor->format, NULL,
00221                   O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
00222          ast_log(LOG_WARNING, "Could not create file %s\n",
00223                   monitor->write_filename);
00224          ast_closestream(monitor->read_stream);
00225          free(monitor);
00226          UNLOCK_IF_NEEDED(chan, need_lock);
00227          return -1;
00228       }
00229       chan->monitor = monitor;
00230       ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00231       /* so we know this call has been monitored in case we need to bill for it or something */
00232       pbx_builtin_setvar_helper(chan, "__MONITORED","true");
00233    } else {
00234       ast_log(LOG_DEBUG,"Cannot start monitoring %s, already monitored\n",
00235                chan->name);
00236       res = -1;
00237    }
00238 
00239    UNLOCK_IF_NEEDED(chan, need_lock);
00240 
00241    return res;
00242 }
00243 
00244 /*
00245  * The file format extensions that Asterisk uses are not all the same as that
00246  * which soxmix expects.  This function ensures that the format used as the
00247  * extension on the filename is something soxmix will understand.
00248  */
00249 static const char *get_soxmix_format(const char *format)
00250 {
00251    const char *res = format;
00252 
00253    if (!strcasecmp(format,"ulaw"))
00254       res = "ul";
00255    if (!strcasecmp(format,"alaw"))
00256       res = "al";
00257    
00258    return res;
00259 }
00260 
00261 /* Stop monitoring a channel */
00262 int ast_monitor_stop(struct ast_channel *chan, int need_lock)
00263 {
00264    int delfiles = 0;
00265 
00266    LOCK_IF_NEEDED(chan, need_lock);
00267 
00268    if (chan->monitor) {
00269       char filename[ FILENAME_MAX ];
00270 
00271       if (chan->monitor->read_stream) {
00272          ast_closestream(chan->monitor->read_stream);
00273       }
00274       if (chan->monitor->write_stream) {
00275          ast_closestream(chan->monitor->write_stream);
00276       }
00277 
00278       if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
00279          if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
00280             snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
00281             if (ast_fileexists(filename, NULL, NULL) > 0) {
00282                ast_filedelete(filename, NULL);
00283             }
00284             ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
00285          } else {
00286             ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
00287          }
00288 
00289          if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
00290             snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
00291             if (ast_fileexists(filename, NULL, NULL) > 0) {
00292                ast_filedelete(filename, NULL);
00293             }
00294             ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
00295          } else {
00296             ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
00297          }
00298       }
00299 
00300       if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
00301          char tmp[1024];
00302          char tmp2[1024];
00303          char tmp3[1024];
00304          int result;
00305          const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
00306          char *name = chan->monitor->filename_base;
00307          int directory = strchr(name, '/') ? 1 : 0;
00308          char *dir = directory ? "" : ast_config_AST_MONITOR_DIR;
00309          const char *execute, *execute_args;
00310 
00311          /* Set the execute application */
00312          execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
00313          if (ast_strlen_zero(execute)) {
00314 #ifdef HAVE_SOXMIX
00315             execute = "nice -n 19 soxmix";
00316 #else
00317             execute = "nice -n 19 sox -m";
00318 #endif
00319             format = get_soxmix_format(format);
00320             delfiles = 1;
00321          } 
00322          execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
00323          if (ast_strlen_zero(execute_args)) {
00324             execute_args = "";
00325          }
00326          
00327          snprintf(tmp, sizeof(tmp), "%s \"%s/%s-in.%s\" \"%s/%s-out.%s\" \"%s/%s.%s\" %s &", execute, dir, name, format, dir, name, format, dir, name, format,execute_args);
00328          if (delfiles) {
00329             snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s/%s-\"* ) &",tmp, dir ,name); /* remove legs when done mixing */
00330             ast_copy_string(tmp, tmp2, sizeof(tmp));
00331          }
00332          if (!ast_strlen_zero(chan->monitor->target_script) && !ast_strlen_zero(chan->monitor->target_url)) {
00333             snprintf(tmp3,sizeof(tmp3), "( %s& nice -19 %s \"%s/%s.%s\" \"%s\" ) &",tmp, chan->monitor->target_script , dir, name, format, chan->monitor->target_url); 
00334             ast_copy_string(tmp, tmp3, sizeof(tmp));
00335          }
00336          ast_log(LOG_NOTICE,"monitor executing %s\n",tmp);
00337          result = ast_safe_system(tmp);
00338          if (result == -1)
00339             ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
00340          manager_event(EVENT_FLAG_CALL, "MonitorStopped",
00341                                "Channel: %s\r\n"
00342                                "Uniqueid: %s\r\n"
00343                    "Result: %d\r\n"
00344                            ,chan->name, chan->uniqueid, result);
00345       }
00346       
00347       free(chan->monitor->format);
00348       free(chan->monitor);
00349       chan->monitor = NULL;
00350    }
00351 
00352    UNLOCK_IF_NEEDED(chan, need_lock);
00353 
00354    return 0;
00355 }
00356 
00357 
00358 /* Pause monitoring of a channel */
00359 int ast_monitor_pause(struct ast_channel *chan)
00360 {
00361    return ast_monitor_set_state(chan, AST_MONITOR_PAUSED);
00362 }
00363 
00364 /* Unpause monitoring of a channel */
00365 int ast_monitor_unpause(struct ast_channel *chan)
00366 {
00367    return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
00368 }
00369 
00370 static int pause_monitor_exec(struct ast_channel *chan, void *data)
00371 {
00372    return ast_monitor_pause(chan);
00373 }
00374 
00375 static int unpause_monitor_exec(struct ast_channel *chan, void *data)
00376 {
00377    return ast_monitor_unpause(chan);
00378 }
00379 
00380 /* Change monitoring filename of a channel */
00381 int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, int need_lock)
00382 {
00383    char tmp[256];
00384    if (ast_strlen_zero(fname_base)) {
00385       ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name);
00386       return -1;
00387    }
00388 
00389    LOCK_IF_NEEDED(chan, need_lock);
00390 
00391    if (chan->monitor) {
00392       int directory = strchr(fname_base, '/') ? 1 : 0;
00393       /* try creating the directory just in case it doesn't exist */
00394       if (directory) {
00395          char *name = strdup(fname_base);
00396          snprintf(tmp, sizeof(tmp), "mkdir -p %s",dirname(name));
00397          free(name);
00398          ast_safe_system(tmp);
00399       }
00400 
00401       snprintf(chan->monitor->filename_base, FILENAME_MAX, "%s/%s", directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
00402       chan->monitor->filename_changed = 1;
00403    } else {
00404       ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base);
00405    }
00406 
00407    UNLOCK_IF_NEEDED(chan, need_lock);
00408 
00409    return 0;
00410 }
00411 
00412 static int start_monitor_exec(struct ast_channel *chan, void *data)
00413 {
00414    char *arg = NULL;
00415    char *format = NULL;
00416    char *fname_base = NULL;
00417    char *options = NULL;
00418    char *delay = NULL;
00419    char *urlprefix = NULL;
00420    char tmp[256];
00421    int joinfiles = 0;
00422    int waitforbridge = 0;
00423    int res = 0;
00424    
00425    /* Parse arguments. */
00426    if (!ast_strlen_zero((char*)data)) {
00427       arg = ast_strdupa((char*)data);
00428       format = arg;
00429       fname_base = strchr(arg, '|');
00430       if (fname_base) {
00431          *fname_base = 0;
00432          fname_base++;
00433          if ((options = strchr(fname_base, '|'))) {
00434             *options = 0;
00435             options++;
00436             if (strchr(options, 'm'))
00437                joinfiles = 1;
00438             if (strchr(options, 'b'))
00439                waitforbridge = 1;
00440          }
00441       }
00442       arg = strchr(format,':');
00443       if (arg) {
00444          *arg++ = 0;
00445          urlprefix = arg;
00446       }
00447    }
00448    if (urlprefix) {
00449       snprintf(tmp,sizeof(tmp) - 1,"%s/%s.%s",urlprefix,fname_base,
00450          ((strcmp(format,"gsm")) ? "wav" : "gsm"));
00451       if (!chan->cdr && !(chan->cdr = ast_cdr_alloc()))
00452          return -1;
00453       ast_cdr_setuserfield(chan, tmp);
00454    }
00455    if (waitforbridge) {
00456       /* We must remove the "b" option if listed.  In principle none of
00457          the following could give NULL results, but we check just to
00458          be pedantic. Reconstructing with checks for 'm' option does not
00459          work if we end up adding more options than 'm' in the future. */
00460       delay = ast_strdupa(data);
00461       options = strrchr(delay, '|');
00462       if (options) {
00463          arg = strchr(options, 'b');
00464          if (arg) {
00465             *arg = 'X';
00466             pbx_builtin_setvar_helper(chan,"AUTO_MONITOR",delay);
00467          }
00468       }
00469       return 0;
00470    }
00471 
00472    res = ast_monitor_start(chan, format, fname_base, NULL, NULL, 1);
00473    if (res < 0)
00474       res = ast_monitor_change_fname(chan, fname_base, 1);
00475    ast_monitor_setjoinfiles(chan, joinfiles);
00476 
00477    return res;
00478 }
00479 
00480 static int stop_monitor_exec(struct ast_channel *chan, void *data)
00481 {
00482    return ast_monitor_stop(chan, 1);
00483 }
00484 
00485 static int change_monitor_exec(struct ast_channel *chan, void *data)
00486 {
00487    return ast_monitor_change_fname(chan, (const char*)data, 1);
00488 }
00489 
00490 static char start_monitor_action_help[] =
00491 "Description: The 'Monitor' action may be used to record the audio on a\n"
00492 "  specified channel.  The following parameters may be used to control\n"
00493 "  this:\n"
00494 "  Channel     - Required.  Used to specify the channel to record.\n"
00495 "  File        - Optional.  Is the name of the file created in the\n"
00496 "                monitor spool directory.  Defaults to the same name\n"
00497 "                as the channel (with slashes replaced with dashes).\n"
00498 "  Format      - Optional.  Is the audio recording format.  Defaults\n"
00499 "                to \"wav\".\n"
00500 "  Mix         - Optional.  Boolean parameter as to whether to mix\n"
00501 "                the input and output channels together after the\n"
00502 "                recording is finished.\n";
00503 
00504 static int start_monitor_action(struct mansession *s, const struct message *m)
00505 {
00506    struct ast_channel *c = NULL;
00507    const char *name = astman_get_header(m, "Channel");
00508    const char *fname = astman_get_header(m, "File");
00509    const char *format = astman_get_header(m, "Format");
00510    const char *mix = astman_get_header(m, "Mix");
00511    const char *uniqueid = astman_get_header(m, "Uniqueid");
00512    const char *target_url = astman_get_header(m, "TargetURL");
00513    const char *target_script = astman_get_header(m, "TargetScript");
00514    char *d;
00515    
00516    if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) {
00517       astman_send_error(s, m, "No channel/uniqueid specified");
00518       return 0;
00519    }
00520 
00521    if (!ast_strlen_zero(uniqueid)) {
00522        c = ast_get_channel_by_uniqueid_locked(uniqueid);
00523        if (!c) {
00524       astman_send_error(s, m, "No such uniqueid");
00525       return 0;
00526        }
00527    } else {
00528        c = ast_get_channel_by_name_locked(name);
00529        if (!c) {
00530       astman_send_error(s, m, "No such channel");
00531       return 0;
00532        }
00533    }
00534 
00535    if (ast_strlen_zero(fname)) {
00536       /* No filename base specified, default to channel name as per CLI */    
00537       if (!(fname = ast_strdup(c->name))) {
00538          astman_send_error(s, m, "Could not start monitoring channel");
00539          ast_channel_unlock(c);
00540          return 0;
00541       }
00542       /* Channels have the format technology/channel_name - have to replace that /  */
00543       if ((d = strchr(fname, '/'))) 
00544          *d = '-';
00545    }
00546    
00547    if (ast_monitor_start(c, format, fname, target_url, target_script, 1)) {
00548       if (ast_monitor_change_fname(c, fname, 1)) {
00549          astman_send_error(s, m, "Could not start monitoring channel");
00550          ast_channel_unlock(c);
00551          return 0;
00552       }
00553    }
00554 
00555    if (ast_true(mix)) {
00556       ast_monitor_setjoinfiles(c, 1);
00557    }
00558 
00559    ast_channel_unlock(c);
00560    astman_send_ack(s, m, "Started monitoring channel");
00561    return 0;
00562 }
00563 
00564 static char stop_monitor_action_help[] =
00565 "Description: The 'StopMonitor' action may be used to end a previously\n"
00566 "  started 'Monitor' action.  The only parameter is 'Channel', the name\n"
00567 "  of the channel monitored.\n";
00568 
00569 static int stop_monitor_action(struct mansession *s, const struct message *m)
00570 {
00571    struct ast_channel *c = NULL;
00572    const char *name = astman_get_header(m, "Channel");
00573    const char *uniqueid = astman_get_header(m, "Uniqueid");
00574    int res;
00575    if (ast_strlen_zero(name)) {
00576       astman_send_error(s, m, "No channel specified");
00577       return 0;
00578    }
00579    if (ast_strlen_zero(name) && ast_strlen_zero(uniqueid)) {
00580       astman_send_error(s, m, "No channel/uniqueid specified");
00581       return 0;
00582    }
00583    if (!ast_strlen_zero(uniqueid)) {
00584        c = ast_get_channel_by_uniqueid_locked(uniqueid);
00585        if (!c) {
00586       astman_send_error(s, m, "No such uniqueid");
00587       return 0;
00588        }
00589    } else {
00590        c = ast_get_channel_by_name_locked(name);
00591        if (!c) {
00592       astman_send_error(s, m, "No such channel");
00593       return 0;
00594        }
00595    }
00596 
00597    res = ast_monitor_stop(c, 1);
00598    ast_channel_unlock(c);
00599    if (res) {
00600       astman_send_error(s, m, "Could not stop monitoring channel");
00601       return 0;
00602    }
00603    astman_send_ack(s, m, "Stopped monitoring channel");
00604    return 0;
00605 }
00606 
00607 static char change_monitor_action_help[] =
00608 "Description: The 'ChangeMonitor' action may be used to change the file\n"
00609 "  started by a previous 'Monitor' action.  The following parameters may\n"
00610 "  be used to control this:\n"
00611 "  Channel     - Required.  Used to specify the channel to record.\n"
00612 "  File        - Required.  Is the new name of the file created in the\n"
00613 "                monitor spool directory.\n";
00614 
00615 static int change_monitor_action(struct mansession *s, const struct message *m)
00616 {
00617    struct ast_channel *c = NULL;
00618    const char *name = astman_get_header(m, "Channel");
00619    const char *fname = astman_get_header(m, "File");
00620    if (ast_strlen_zero(name)) {
00621       astman_send_error(s, m, "No channel specified");
00622       return 0;
00623    }
00624    if (ast_strlen_zero(fname)) {
00625       astman_send_error(s, m, "No filename specified");
00626       return 0;
00627    }
00628    c = ast_get_channel_by_name_locked(name);
00629    if (!c) {
00630       astman_send_error(s, m, "No such channel");
00631       return 0;
00632    }
00633    if (ast_monitor_change_fname(c, fname, 1)) {
00634       astman_send_error(s, m, "Could not change monitored filename of channel");
00635       ast_channel_unlock(c);
00636       return 0;
00637    }
00638    ast_channel_unlock(c);
00639    astman_send_ack(s, m, "Changed monitor filename");
00640    return 0;
00641 }
00642 
00643 void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
00644 {
00645    if (chan->monitor)
00646       chan->monitor->joinfiles = turnon;
00647 }
00648 
00649 #define IS_NULL_STRING(string) ((!(string)) || (ast_strlen_zero((string))))
00650 
00651 enum MONITOR_PAUSING_ACTION
00652 {
00653    MONITOR_ACTION_PAUSE,
00654    MONITOR_ACTION_UNPAUSE
00655 };
00656      
00657 static int do_pause_or_unpause(struct mansession *s, const struct message *m, int action)
00658 {
00659    struct ast_channel *c = NULL;
00660    const char *name = astman_get_header(m, "Channel");
00661    
00662    if (IS_NULL_STRING(name)) {
00663       astman_send_error(s, m, "No channel specified");
00664       return -1;
00665    }
00666    
00667    c = ast_get_channel_by_name_locked(name);
00668    if (!c) {
00669       astman_send_error(s, m, "No such channel");
00670       return -1;
00671    }
00672 
00673    if (action == MONITOR_ACTION_PAUSE)
00674       ast_monitor_pause(c);
00675    else
00676       ast_monitor_unpause(c);
00677    
00678    ast_channel_unlock(c);
00679    astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel"));
00680    return 0;   
00681 }
00682 
00683 static char pause_monitor_action_help[] =
00684    "Description: The 'PauseMonitor' action may be used to temporarily stop the\n"
00685    " recording of a channel.  The following parameters may\n"
00686    " be used to control this:\n"
00687    "  Channel     - Required.  Used to specify the channel to record.\n";
00688 
00689 static int pause_monitor_action(struct mansession *s, const struct message *m)
00690 {
00691    return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
00692 }
00693 
00694 static char unpause_monitor_action_help[] =
00695    "Description: The 'UnpauseMonitor' action may be used to re-enable recording\n"
00696    "  of a channel after calling PauseMonitor.  The following parameters may\n"
00697    "  be used to control this:\n"
00698    "  Channel     - Required.  Used to specify the channel to record.\n";
00699 
00700 static int unpause_monitor_action(struct mansession *s, const struct message *m)
00701 {
00702    return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
00703 }
00704    
00705 
00706 static int load_module(void)
00707 {
00708    ast_register_application("Monitor", start_monitor_exec, monitor_synopsis, monitor_descrip);
00709    ast_register_application("StopMonitor", stop_monitor_exec, stopmonitor_synopsis, stopmonitor_descrip);
00710    ast_register_application("ChangeMonitor", change_monitor_exec, changemonitor_synopsis, changemonitor_descrip);
00711    ast_register_application("PauseMonitor", pause_monitor_exec, pausemonitor_synopsis, pausemonitor_descrip);
00712    ast_register_application("UnpauseMonitor", unpause_monitor_exec, unpausemonitor_synopsis, unpausemonitor_descrip);
00713    ast_manager_register2("Monitor", EVENT_FLAG_CALL, start_monitor_action, monitor_synopsis, start_monitor_action_help);
00714    ast_manager_register2("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action, stopmonitor_synopsis, stop_monitor_action_help);
00715    ast_manager_register2("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action, changemonitor_synopsis, change_monitor_action_help);
00716    ast_manager_register2("PauseMonitor", EVENT_FLAG_CALL, pause_monitor_action, pausemonitor_synopsis, pause_monitor_action_help);
00717    ast_manager_register2("UnpauseMonitor", EVENT_FLAG_CALL, unpause_monitor_action, unpausemonitor_synopsis, unpause_monitor_action_help);
00718 
00719    return 0;
00720 }
00721 
00722 static int unload_module(void)
00723 {
00724    ast_unregister_application("Monitor");
00725    ast_unregister_application("StopMonitor");
00726    ast_unregister_application("ChangeMonitor");
00727    ast_unregister_application("PauseMonitor");
00728    ast_unregister_application("UnpauseMonitor");
00729    ast_manager_unregister("Monitor");
00730    ast_manager_unregister("StopMonitor");
00731    ast_manager_unregister("ChangeMonitor");
00732    ast_manager_unregister("PauseMonitor");
00733    ast_manager_unregister("UnpauseMonitor");
00734 
00735    return 0;
00736 }
00737 
00738 /* usecount semantics need to be defined */
00739 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Monitoring Resource",
00740       .load = load_module,
00741       .unload = unload_module,
00742       );

Generated on Fri Sep 25 19:28:15 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.5