diff options
-rw-r--r-- | UPGRADE.txt | 4 | ||||
-rw-r--r-- | apps/app_queue.c | 124 | ||||
-rw-r--r-- | configs/queues.conf.sample | 56 |
3 files changed, 164 insertions, 20 deletions
diff --git a/UPGRADE.txt b/UPGRADE.txt index 953a66133..07f68b20b 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -93,6 +93,10 @@ Applications: option, it will default to "no" to keep backward compatability with the old behavior. +* The app_queue application now has the ability to use MixMonitor to + record conversations queue members are having with queue callers. Please + see configs/queues.conf.sample for more information on this option. + * ast_play_and_record would attempt to cancel the recording if a DTMF '0' was received. This behavior was not documented in most of the applications that used ast_play_and_record and the return codes from diff --git a/apps/app_queue.c b/apps/app_queue.c index c49ddc038..4e960d2cb 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -239,6 +239,9 @@ static int use_weight = 0; /*! \brief queues.conf [general] option */ static int autofill_default = 0; +/*! \brief queues.conf [general] option */ +static int montype_default = 0; + enum queue_result { QUEUE_UNKNOWN = 0, QUEUE_TIMEOUT = 1, @@ -348,6 +351,7 @@ struct ast_call_queue { int servicelevel; /*!< seconds setting for servicelevel*/ int callscompletedinsl; /*!< Number of calls answered with servicelevel*/ char monfmt[8]; /*!< Format to use when recording calls */ + int montype; /*!< Monitor type Monitor vs. MixMonitor */ char sound_next[80]; /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */ char sound_thereare[80]; /*!< Sound file: "There are currently" (def. queue-thereare) */ char sound_calls[80]; /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/ @@ -584,6 +588,7 @@ static void init_queue(struct ast_call_queue *q) q->ringinuse = 1; q->setinterfacevar = 0; q->autofill = autofill_default; + q->montype = montype_default; q->moh[0] = '\0'; q->announce[0] = '\0'; q->context[0] = '\0'; @@ -711,6 +716,9 @@ static void queue_set_param(struct ast_call_queue *q, const char *param, const c q->wrapuptime = atoi(val); } else if (!strcasecmp(param, "autofill")) { q->autofill = ast_true(val); + } else if (!strcasecmp(param, "monitor-type")) { + if (!strcasecmp(val, "mixmonitor")) + q->montype = 1; } else if (!strcasecmp(param, "autopause")) { q->autopause = ast_true(val); } else if (!strcasecmp(param, "maxlen")) { @@ -1251,9 +1259,8 @@ static void leave_queue(struct queue_ent *qe) manager_event(EVENT_FLAG_CALL, "Leave", "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n", qe->chan->name, q->name, q->count); -#if 0 -ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); -#endif + if (option_debug) + ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name ); /* Take us out of the queue */ if (prev) prev->next = cur->next; @@ -2098,6 +2105,15 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce char nondataquality = 1; char *agiexec = NULL; int ret = 0; + const char *monitorfilename; + const char *monitor_exec; + const char *monitor_options; + char tmpid[256], tmpid2[256]; + char meid[1024], meid2[1024]; + char mixmonargs[1512]; + struct ast_app *mixmonapp = NULL; + char *p; + memset(&bridge_config, 0, sizeof(bridge_config)); time(&now); @@ -2283,23 +2299,89 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce } /* Begin Monitoring */ if (qe->parent->monfmt && *qe->parent->monfmt) { - const char *monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); - if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) - which = qe->chan; - else - which = peer; - if (monitorfilename) - ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 ); - else if (qe->chan->cdr) - ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 ); - else { - /* Last ditch effort -- no CDR, make up something */ - char tmpid[256]; - snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); - ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 ); + if (!qe->parent->montype) { + if (option_debug) + ast_log(LOG_DEBUG, "Starting Monitor as requested.\n"); + monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); + if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) + which = qe->chan; + else + which = peer; + if (monitorfilename) + ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 ); + else if (qe->chan->cdr) + ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 ); + else { + /* Last ditch effort -- no CDR, make up something */ + snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); + ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 ); + } + if (qe->parent->monjoin) + ast_monitor_setjoinfiles(which, 1); + } else { + if (option_debug) + ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n"); + monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); + if (!monitorfilename) { + if (qe->chan->cdr) + ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1); + else + snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); + } else { + ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1); + for (p = tmpid2; *p ; p++) { + if (*p == '^' && *(p+1) == '{') { + *p = '$'; + } + } + + pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1); + } + + monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"); + monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"); + + if (monitor_exec) { + ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1); + for (p = meid2; *p ; p++) { + if (*p == '^' && *(p+1) == '{') { + *p = '$'; + } + } + pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1); + } + + snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt); + + mixmonapp = pbx_findapp("MixMonitor"); + + if (strchr(tmpid2, '|')) { + ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n"); + mixmonapp = NULL; + } + + if (strchr(monitor_options, '|')) { + ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n"); + mixmonapp = NULL; + } + + if (mixmonapp) { + if (!ast_strlen_zero(monitor_exec) && !ast_strlen_zero(monitor_options)) + snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec); + else if (!ast_strlen_zero(monitor_options)) + snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options); + else + snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b", tmpid2); + + if (option_debug) + ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs); + + ret = pbx_exec(qe->chan, mixmonapp, mixmonargs); + + } else + ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n"); + } - if (qe->parent->monjoin) - ast_monitor_setjoinfiles(which, 1); } /* Drop out of the queue at this point, to prepare for next caller */ leave_queue(qe); @@ -3386,6 +3468,10 @@ static void reload_queues(void) autofill_default = 0; if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) autofill_default = ast_true(general_val); + montype_default = 0; + if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) + if (!strcasecmp(general_val, "mixmonitor")) + montype_default = 1; } else { /* Define queue */ /* Look for an existing one */ AST_LIST_TRAVERSE(&queues, q, list) { diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample index f1cdeba4b..ab88d18bf 100644 --- a/configs/queues.conf.sample +++ b/configs/queues.conf.sample @@ -28,6 +28,20 @@ persistentmembers = yes ; autofill = yes ; +; Monitor Type +; By setting monitor-type = MixMonitor, when specifying monitor-format +; to enable recording of queue member conversations, app_queue will +; now use the new MixMonitor application instead of Monitor so +; the concept of "joining/mixing" the in/out files now goes away +; when this is enabled. You can set the default type for all queues +; here, and then also change monitor-type for individual queues within +; queue by using the same configuation parameter within a queue +; configuration block. If you do not specify or comment out this option, +; it will default to the old 'Monitor' behavior to keep backward +; compatibility. +; +monitor-type = MixMonitor +; ; Note that a timeout to fail out of a queue may be passed as part of ; an application call from extensions.conf: ; Queue(queuename|[options]|[optionalurl]|[announceoverride]|[timeout]) @@ -161,7 +175,7 @@ autofill = yes ; ("All reps busy / wait for next") ;periodic-announce = queue-periodic-announce ; -; Calls may be recorded using Asterisk's monitor resource +; Calls may be recorded using Asterisk's monitor/MixMonitor resource ; This can be enabled from within the Queue application, starting recording ; when the call is actually picked up; thus, only successful calls are ; recorded, and you are not recording while people are listening to MOH. @@ -172,8 +186,24 @@ autofill = yes ; Set(MONITOR_FILENAME=foo) ; Otherwise it will use MONITOR_FILENAME=${UNIQUEID} ; +; Pick any one valid extension for monitor format recording. If you leave +; monitor-format commented out, it will not record calls. +; ; monitor-format = gsm|wav|wav49 ; +; Monitor Type +; By setting monitor-type = MixMonitor, when specifying monitor-format +; to enable recording of queue member conversations, app_queue will +; now use the new MixMonitor application instead of Monitor so +; the concept of "joining/mixing" the in/out files now goes away +; when this is enabled. If you do not specify or comment out this option, +; it will default to the old 'Monitor' behavior to keep backward +; compatibility. +; +; monitor-type = MixMonitor +; +; ----------------------- TYPE MONITOR OPTIONS -------------------------------- +; ; If you wish to have the two files joined together when the call ends, set this ; to yes. ; @@ -187,6 +217,30 @@ autofill = yes ; strict - callers cannot join a queue with no members or only unavailable ; members ; +; ----------------------- TYPE MIXMONITOR OPTIONS ----------------------------- +; +; +; You can specify the options supplied to MixMonitor by calling +; Set(MONITOR_OPTIONS=av(<x>)V(<x>)W(<x>)) +; The 'b' option for MixMonitor (only save audio to the file while bridged) is +; implied. +; +; You can specify a post recording command to be executed after the end of +; recording by calling +; Set(MONITOR_EXEC=mv /var/spool/asterisk/monitor/^{MONITOR_FILENAME} /tmp/^{MONITOR_FILENAME}) +; +; The command specified within the contents of MONITOR_EXEC will be executed when +; the recording is over. Any strings matching ^{X} will be unescaped to ${X} and +; all variables will be evaluated just prior to recording being started. +; +; The contents of MONITOR_FILENAME will also be unescaped from ^{X} to ${X} and +; all variables will be evaluated just prior to recording being started. +; +; +; +; +; +; ; joinempty = yes ; ; If you wish to remove callers from the queue when new callers cannot join, |