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

Generated on Fri Sep 11 13:45:01 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7