Merged revisions 67597 via svnmerge from
[asterisk/asterisk.git] / res / res_monitor.c
index 4f47a65..7b69b60 100644 (file)
  * \author Mark Spencer <markster@digium.com>
  */
  
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <libgen.h>            /* dirname() */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+#include <libgen.h>
 
 #include "asterisk/lock.h"
 #include "asterisk/channel.h"
@@ -47,17 +47,18 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/app.h"
 #include "asterisk/utils.h"
 #include "asterisk/config.h"
+#include "asterisk/options.h"
 
 AST_MUTEX_DEFINE_STATIC(monitorlock);
 
 #define LOCK_IF_NEEDED(lock, needed) do { \
        if (needed) \
-               ast_mutex_lock(lock); \
+               ast_channel_lock(lock); \
        } while(0)
 
 #define UNLOCK_IF_NEEDED(lock, needed) do { \
        if (needed) \
-               ast_mutex_unlock(lock); \
+               ast_channel_unlock(lock); \
        } while (0)
 
 static unsigned long seq = 0;
@@ -112,13 +113,13 @@ static char *unpausemonitor_descrip = "UnpauseMonitor\n"
 
 static int ast_monitor_set_state(struct ast_channel *chan, int state)
 {
-       LOCK_IF_NEEDED(&chan->lock, 1);
+       LOCK_IF_NEEDED(chan, 1);
        if (!chan->monitor) {
-               UNLOCK_IF_NEEDED(&chan->lock, 1);
+               UNLOCK_IF_NEEDED(chan, 1);
                return -1;
        }
        chan->monitor->state = state;
-       UNLOCK_IF_NEEDED(&chan->lock, 1);
+       UNLOCK_IF_NEEDED(chan, 1);
        return 0;
 }
 
@@ -129,7 +130,7 @@ int ast_monitor_start(      struct ast_channel *chan, const char *format_spec,
        int res = 0;
        char tmp[256];
 
-       LOCK_IF_NEEDED(&chan->lock, need_lock);
+       LOCK_IF_NEEDED(chan, need_lock);
 
        if (!(chan->monitor)) {
                struct ast_channel_monitor *monitor;
@@ -144,7 +145,7 @@ int ast_monitor_start(      struct ast_channel *chan, const char *format_spec,
                }
 
                if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
-                       UNLOCK_IF_NEEDED(&chan->lock, need_lock);
+                       UNLOCK_IF_NEEDED(chan, need_lock);
                        return -1;
                }
 
@@ -172,17 +173,13 @@ int ast_monitor_start(    struct ast_channel *chan, const char *format_spec,
                        seq++;
                        ast_mutex_unlock(&monitorlock);
 
-                       if((channel_name = ast_strdupa(chan->name))) {
-                               while((p = strchr(channel_name, '/'))) {
-                                       *p = '-';
-                               }
-                               snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
-                                                ast_config_AST_MONITOR_DIR, (int)time(NULL),channel_name);
-                               monitor->filename_changed = 1;
-                       } else {
-                               ast_log(LOG_ERROR,"Failed to allocate Memory\n");
-                               return -1;
+                       channel_name = ast_strdupa(chan->name);
+                       while ((p = strchr(channel_name, '/'))) {
+                               *p = '-';
                        }
+                       snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
+                                        ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
+                       monitor->filename_changed = 1;
                }
 
                monitor->stop = ast_monitor_stop;
@@ -200,11 +197,11 @@ int ast_monitor_start(    struct ast_channel *chan, const char *format_spec,
                }
                if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
                                                monitor->format, NULL,
-                                               O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
+                                               O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
                        ast_log(LOG_WARNING, "Could not create file %s\n",
                                                monitor->read_filename);
                        free(monitor);
-                       ast_channel_unlock(chan);
+                       UNLOCK_IF_NEEDED(chan, need_lock);
                        return -1;
                }
                if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
@@ -212,12 +209,12 @@ int ast_monitor_start(    struct ast_channel *chan, const char *format_spec,
                }
                if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
                                                monitor->format, NULL,
-                                               O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
+                                               O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
                        ast_log(LOG_WARNING, "Could not create file %s\n",
                                                monitor->write_filename);
                        ast_closestream(monitor->read_stream);
                        free(monitor);
-                       ast_channel_unlock(chan);
+                       UNLOCK_IF_NEEDED(chan, need_lock);
                        return -1;
                }
                chan->monitor = monitor;
@@ -225,22 +222,40 @@ int ast_monitor_start(    struct ast_channel *chan, const char *format_spec,
                /* so we know this call has been monitored in case we need to bill for it or something */
                pbx_builtin_setvar_helper(chan, "__MONITORED","true");
        } else {
-               ast_log(LOG_DEBUG,"Cannot start monitoring %s, already monitored\n",
-                                       chan->name);
+               if (option_debug)
+                       ast_log(LOG_DEBUG,"Cannot start monitoring %s, already monitored\n",
+                                               chan->name);
                res = -1;
        }
 
-       UNLOCK_IF_NEEDED(&chan->lock, need_lock);
+       UNLOCK_IF_NEEDED(chan, need_lock);
 
        return res;
 }
 
+/*
+ * The file format extensions that Asterisk uses are not all the same as that
+ * which soxmix expects.  This function ensures that the format used as the
+ * extension on the filename is something soxmix will understand.
+ */
+static const char *get_soxmix_format(const char *format)
+{
+       const char *res = format;
+
+       if (!strcasecmp(format,"ulaw"))
+               res = "ul";
+       if (!strcasecmp(format,"alaw"))
+               res = "al";
+       
+       return res;
+}
+
 /* Stop monitoring a channel */
 int ast_monitor_stop(struct ast_channel *chan, int need_lock)
 {
        int delfiles = 0;
 
-       LOCK_IF_NEEDED(&chan->lock, need_lock);
+       LOCK_IF_NEEDED(chan, need_lock);
 
        if (chan->monitor) {
                char filename[ FILENAME_MAX ];
@@ -277,7 +292,7 @@ int ast_monitor_stop(struct ast_channel *chan, int need_lock)
                if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
                        char tmp[1024];
                        char tmp2[1024];
-                       char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
+                       const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
                        char *name = chan->monitor->filename_base;
                        int directory = strchr(name, '/') ? 1 : 0;
                        char *dir = directory ? "" : ast_config_AST_MONITOR_DIR;
@@ -287,6 +302,7 @@ int ast_monitor_stop(struct ast_channel *chan, int need_lock)
                        execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
                        if (ast_strlen_zero(execute)) { 
                                execute = "nice -n 19 soxmix";
+                               format = get_soxmix_format(format);
                                delfiles = 1;
                        } 
                        execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
@@ -299,7 +315,8 @@ int ast_monitor_stop(struct ast_channel *chan, int need_lock)
                                snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s/%s-\"* ) &",tmp, dir ,name); /* remove legs when done mixing */
                                ast_copy_string(tmp, tmp2, sizeof(tmp));
                        }
-                       ast_log(LOG_DEBUG,"monitor executing %s\n",tmp);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG,"monitor executing %s\n",tmp);
                        if (ast_safe_system(tmp) == -1)
                                ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
                }
@@ -309,7 +326,7 @@ int ast_monitor_stop(struct ast_channel *chan, int need_lock)
                chan->monitor = NULL;
        }
 
-       UNLOCK_IF_NEEDED(&chan->lock, need_lock);
+       UNLOCK_IF_NEEDED(chan, need_lock);
 
        return 0;
 }
@@ -327,12 +344,12 @@ int ast_monitor_unpause(struct ast_channel *chan)
        return ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
 }
 
-int pause_monitor_exec(struct ast_channel *chan, void *data)
+static int pause_monitor_exec(struct ast_channel *chan, void *data)
 {
        return ast_monitor_pause(chan);
 }
 
-int unpause_monitor_exec(struct ast_channel *chan, void *data)
+static int unpause_monitor_exec(struct ast_channel *chan, void *data)
 {
        return ast_monitor_unpause(chan);
 }
@@ -342,11 +359,11 @@ int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, i
 {
        char tmp[256];
        if (ast_strlen_zero(fname_base)) {
-               ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null", chan->name);
+               ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null\n", chan->name);
                return -1;
        }
 
-       LOCK_IF_NEEDED(&chan->lock, need_lock);
+       LOCK_IF_NEEDED(chan, need_lock);
 
        if (chan->monitor) {
                int directory = strchr(fname_base, '/') ? 1 : 0;
@@ -359,11 +376,12 @@ int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, i
                }
 
                snprintf(chan->monitor->filename_base, FILENAME_MAX, "%s/%s", directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
+               chan->monitor->filename_changed = 1;
        } else {
                ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base);
        }
 
-       UNLOCK_IF_NEEDED(&chan->lock, need_lock);
+       UNLOCK_IF_NEEDED(chan, need_lock);
 
        return 0;
 }
@@ -416,15 +434,13 @@ static int start_monitor_exec(struct ast_channel *chan, void *data)
                   the following could give NULL results, but we check just to
                   be pedantic. Reconstructing with checks for 'm' option does not
                   work if we end up adding more options than 'm' in the future. */
-               delay = ast_strdupa((char*)data);
-               if (delay) {
-                       options = strrchr(delay, '|');
-                       if (options) {
-                               arg = strchr(options, 'b');
-                               if (arg) {
-                                       *arg = 'X';
-                                       pbx_builtin_setvar_helper(chan,"AUTO_MONITOR",delay);
-                               }
+               delay = ast_strdupa(data);
+               options = strrchr(delay, '|');
+               if (options) {
+                       arg = strchr(options, 'b');
+                       if (arg) {
+                               *arg = 'X';
+                               pbx_builtin_setvar_helper(chan,"AUTO_MONITOR",delay);
                        }
                }
                return 0;
@@ -462,13 +478,13 @@ static char start_monitor_action_help[] =
 "                the input and output channels together after the\n"
 "                recording is finished.\n";
 
-static int start_monitor_action(struct mansession *s, struct message *m)
+static int start_monitor_action(struct mansession *s, const struct message *m)
 {
        struct ast_channel *c = NULL;
-       char *name = astman_get_header(m, "Channel");
-       char *fname = astman_get_header(m, "File");
-       char *format = astman_get_header(m, "Format");
-       char *mix = astman_get_header(m, "Mix");
+       const char *name = astman_get_header(m, "Channel");
+       const char *fname = astman_get_header(m, "File");
+       const char *format = astman_get_header(m, "Format");
+       const char *mix = astman_get_header(m, "Mix");
        char *d;
        
        if (ast_strlen_zero(name)) {
@@ -515,10 +531,10 @@ static char stop_monitor_action_help[] =
 "  started 'Monitor' action.  The only parameter is 'Channel', the name\n"
 "  of the channel monitored.\n";
 
-static int stop_monitor_action(struct mansession *s, struct message *m)
+static int stop_monitor_action(struct mansession *s, const struct message *m)
 {
        struct ast_channel *c = NULL;
-       char *name = astman_get_header(m, "Channel");
+       const char *name = astman_get_header(m, "Channel");
        int res;
        if (ast_strlen_zero(name)) {
                astman_send_error(s, m, "No channel specified");
@@ -547,11 +563,11 @@ static char change_monitor_action_help[] =
 "  File        - Required.  Is the new name of the file created in the\n"
 "                monitor spool directory.\n";
 
-static int change_monitor_action(struct mansession *s, struct message *m)
+static int change_monitor_action(struct mansession *s, const struct message *m)
 {
        struct ast_channel *c = NULL;
-       char *name = astman_get_header(m, "Channel");
-       char *fname = astman_get_header(m, "File");
+       const char *name = astman_get_header(m, "Channel");
+       const char *fname = astman_get_header(m, "File");
        if (ast_strlen_zero(name)) {
                astman_send_error(s, m, "No channel specified");
                return 0;
@@ -581,20 +597,18 @@ void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
                chan->monitor->joinfiles = turnon;
 }
 
-#define IS_NULL_STRING(string) ((!(string)) || (ast_strlen_zero((string))))
-
 enum MONITOR_PAUSING_ACTION
 {
        MONITOR_ACTION_PAUSE,
        MONITOR_ACTION_UNPAUSE
 };
          
-static int do_pause_or_unpause(struct mansession *s, struct message *m, int action)
+static int do_pause_or_unpause(struct mansession *s, const struct message *m, int action)
 {
        struct ast_channel *c = NULL;
-       char *name = astman_get_header(m, "Channel");
+       const char *name = astman_get_header(m, "Channel");
        
-       if (IS_NULL_STRING(name)) {
+       if (ast_strlen_zero(name)) {
                astman_send_error(s, m, "No channel specified");
                return -1;
        }
@@ -611,7 +625,7 @@ static int do_pause_or_unpause(struct mansession *s, struct message *m, int acti
                ast_monitor_unpause(c);
        
        ast_channel_unlock(c);
-       astman_send_ack(s, m, "Paused monitoring of the channel");
+       astman_send_ack(s, m, (action == MONITOR_ACTION_PAUSE ? "Paused monitoring of the channel" : "Unpaused monitoring of the channel"));
        return 0;       
 }
 
@@ -621,7 +635,7 @@ static char pause_monitor_action_help[] =
        " be used to control this:\n"
        "  Channel     - Required.  Used to specify the channel to record.\n";
 
-static int pause_monitor_action(struct mansession *s, struct message *m)
+static int pause_monitor_action(struct mansession *s, const struct message *m)
 {
        return do_pause_or_unpause(s, m, MONITOR_ACTION_PAUSE);
 }
@@ -632,13 +646,13 @@ static char unpause_monitor_action_help[] =
        "  be used to control this:\n"
        "  Channel     - Required.  Used to specify the channel to record.\n";
 
-static int unpause_monitor_action(struct mansession *s, struct message *m)
+static int unpause_monitor_action(struct mansession *s, const struct message *m)
 {
        return do_pause_or_unpause(s, m, MONITOR_ACTION_UNPAUSE);
 }
        
 
-static int load_module(void *mod)
+static int load_module(void)
 {
        ast_register_application("Monitor", start_monitor_exec, monitor_synopsis, monitor_descrip);
        ast_register_application("StopMonitor", stop_monitor_exec, stopmonitor_synopsis, stopmonitor_descrip);
@@ -654,7 +668,7 @@ static int load_module(void *mod)
        return 0;
 }
 
-static int unload_module(void *mod)
+static int unload_module(void)
 {
        ast_unregister_application("Monitor");
        ast_unregister_application("StopMonitor");
@@ -664,20 +678,14 @@ static int unload_module(void *mod)
        ast_manager_unregister("Monitor");
        ast_manager_unregister("StopMonitor");
        ast_manager_unregister("ChangeMonitor");
-       ast_unregister_application("PauseMonitor");
-       ast_unregister_application("UnpauseMonitor");
+       ast_manager_unregister("PauseMonitor");
+       ast_manager_unregister("UnpauseMonitor");
 
        return 0;
 }
 
-static const char *description(void)
-{
-       return "Call Monitoring Resource";
-}
-
-static const char *key(void)
-{
-       return ASTERISK_GPL_KEY;
-}
-
-STD_MOD(MOD_0 | NO_USECOUNT | NO_UNLOAD, NULL, NULL, NULL);    /* MOD_0 because it exports some symbols */
+/* usecount semantics need to be defined */
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Monitoring Resource",
+               .load = load_module,
+               .unload = unload_module,
+               );