(mix)monitor: Add options to enable a periodic beep

Add an option to enable a periodic beep to be played into a call if it
is being recorded.  If enabled, it uses the PERIODIC_HOOK() function
internally to play the 'beep' prompt into the call at a specified
interval.  This option is provided for both Monitor() and
MixMonitor().

Review: https://reviewboard.asterisk.org/r/3424/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@412427 65c4cc65-6c06-0410-ace0-fbb531ad65f3
changes/97/197/1
Russell Bryant 12 years ago
parent ba1db5d8f5
commit 5b7a769fd8

@ -16,6 +16,8 @@ Applications
-------------------------- --------------------------
* Record application now has an option 'o' which allows 0 to act as an exit * Record application now has an option 'o' which allows 0 to act as an exit
key setting the RECORD_STATUS variable to 'OPERATOR' instead of 'DTMF' key setting the RECORD_STATUS variable to 'OPERATOR' instead of 'DTMF'
* Monitor() - A new option, B(), has been added that will turn on a periodic
beep while the call is being recorded.
Functions Functions
-------------------------- --------------------------
@ -85,6 +87,8 @@ MixMonitor
------------------------- -------------------------
* A new function, MIXMONITOR, has been added to allow access to individual * A new function, MIXMONITOR, has been added to allow access to individual
instances of MixMonitor on a channel. instances of MixMonitor on a channel.
* A new option, B(), has been added that will turn on a periodic beep while the
call is being recorded.
Channel Drivers Channel Drivers

@ -57,6 +57,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/linkedlists.h" #include "asterisk/linkedlists.h"
#include "asterisk/test.h" #include "asterisk/test.h"
#include "asterisk/mixmonitor.h" #include "asterisk/mixmonitor.h"
#include "asterisk/beep.h"
/*** DOCUMENTATION /*** DOCUMENTATION
<application name="MixMonitor" language="en_US"> <application name="MixMonitor" language="en_US">
@ -83,6 +84,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
channel is not optimized away. To do this, be sure to call your Local channel with the channel is not optimized away. To do this, be sure to call your Local channel with the
<literal>/n</literal> option. For example: Dial(Local/start@mycontext/n)</para></note> <literal>/n</literal> option. For example: Dial(Local/start@mycontext/n)</para></note>
</option> </option>
<option name="B">
<para>Play a periodic beep while this call is being recorded.</para>
<argument name="interval"><para>Interval, in seconds. Default is 15.</para></argument>
</option>
<option name="v"> <option name="v">
<para>Adjust the <emphasis>heard</emphasis> volume by a factor of <replaceable>x</replaceable> <para>Adjust the <emphasis>heard</emphasis> volume by a factor of <replaceable>x</replaceable>
(range <literal>-4</literal> to <literal>4</literal>)</para> (range <literal>-4</literal> to <literal>4</literal>)</para>
@ -319,6 +324,7 @@ enum mixmonitor_flags {
MUXFLAG_COMBINED = (1 << 8), MUXFLAG_COMBINED = (1 << 8),
MUXFLAG_UID = (1 << 9), MUXFLAG_UID = (1 << 9),
MUXFLAG_VMRECIPIENTS = (1 << 10), MUXFLAG_VMRECIPIENTS = (1 << 10),
MUXFLAG_BEEP = (1 << 11),
}; };
enum mixmonitor_args { enum mixmonitor_args {
@ -329,12 +335,14 @@ enum mixmonitor_args {
OPT_ARG_READNAME, OPT_ARG_READNAME,
OPT_ARG_UID, OPT_ARG_UID,
OPT_ARG_VMRECIPIENTS, OPT_ARG_VMRECIPIENTS,
OPT_ARG_BEEP_INTERVAL,
OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */ OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
}; };
AST_APP_OPTIONS(mixmonitor_opts, { AST_APP_OPTIONS(mixmonitor_opts, {
AST_APP_OPTION('a', MUXFLAG_APPEND), AST_APP_OPTION('a', MUXFLAG_APPEND),
AST_APP_OPTION('b', MUXFLAG_BRIDGED), AST_APP_OPTION('b', MUXFLAG_BRIDGED),
AST_APP_OPTION_ARG('B', MUXFLAG_BEEP, OPT_ARG_BEEP_INTERVAL),
AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME), AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME), AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME), AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
@ -361,6 +369,7 @@ struct mixmonitor_ds {
unsigned int samp_rate; unsigned int samp_rate;
char *filename; char *filename;
char *beep_id;
}; };
/*! /*!
@ -405,6 +414,7 @@ static void mixmonitor_ds_destroy(void *data)
mixmonitor_ds->audiohook = NULL; mixmonitor_ds->audiohook = NULL;
mixmonitor_ds->destruction_ok = 1; mixmonitor_ds->destruction_ok = 1;
ast_free(mixmonitor_ds->filename); ast_free(mixmonitor_ds->filename);
ast_free(mixmonitor_ds->beep_id);
ast_cond_signal(&mixmonitor_ds->destruction_condition); ast_cond_signal(&mixmonitor_ds->destruction_condition);
ast_mutex_unlock(&mixmonitor_ds->lock); ast_mutex_unlock(&mixmonitor_ds->lock);
} }
@ -772,7 +782,7 @@ static void *mixmonitor_thread(void *obj)
return NULL; return NULL;
} }
static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id) static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
{ {
struct ast_datastore *datastore = NULL; struct ast_datastore *datastore = NULL;
struct mixmonitor_ds *mixmonitor_ds; struct mixmonitor_ds *mixmonitor_ds;
@ -799,6 +809,9 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel
mixmonitor_ds->samp_rate = 8000; mixmonitor_ds->samp_rate = 8000;
mixmonitor_ds->audiohook = &mixmonitor->audiohook; mixmonitor_ds->audiohook = &mixmonitor->audiohook;
mixmonitor_ds->filename = ast_strdup(mixmonitor->filename); mixmonitor_ds->filename = ast_strdup(mixmonitor->filename);
if (!ast_strlen_zero(beep_id)) {
mixmonitor_ds->beep_id = ast_strdup(beep_id);
}
datastore->data = mixmonitor_ds; datastore->data = mixmonitor_ds;
ast_channel_lock(chan); ast_channel_lock(chan);
@ -813,7 +826,7 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
unsigned int flags, int readvol, int writevol, unsigned int flags, int readvol, int writevol,
const char *post_process, const char *filename_write, const char *post_process, const char *filename_write,
char *filename_read, const char *uid_channel_var, char *filename_read, const char *uid_channel_var,
const char *recipients) const char *recipients, const char *beep_id)
{ {
pthread_t thread; pthread_t thread;
struct mixmonitor *mixmonitor; struct mixmonitor *mixmonitor;
@ -872,7 +885,7 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
mixmonitor->filename_read = ast_strdup(filename_read); mixmonitor->filename_read = ast_strdup(filename_read);
} }
if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id)) { if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
ast_autochan_destroy(mixmonitor->autochan); ast_autochan_destroy(mixmonitor->autochan);
mixmonitor_free(mixmonitor); mixmonitor_free(mixmonitor);
ast_free(datastore_id); ast_free(datastore_id);
@ -973,6 +986,7 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
char *filename_write = NULL; char *filename_write = NULL;
char filename_buffer[1024] = ""; char filename_buffer[1024] = "";
char *uid_channel_var = NULL; char *uid_channel_var = NULL;
char beep_id[64] = "";
struct ast_flags flags = { 0 }; struct ast_flags flags = { 0 };
char *recipients = NULL; char *recipients = NULL;
@ -1046,6 +1060,21 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
if (ast_test_flag(&flags, MUXFLAG_UID)) { if (ast_test_flag(&flags, MUXFLAG_UID)) {
uid_channel_var = opts[OPT_ARG_UID]; uid_channel_var = opts[OPT_ARG_UID];
} }
if (ast_test_flag(&flags, MUXFLAG_BEEP)) {
const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
unsigned int interval = 15;
if (sscanf(interval_str, "%30u", &interval) != 1) {
ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
interval_str, interval);
}
if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
return -1;
}
}
} }
/* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */ /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
@ -1072,7 +1101,8 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
filename_write, filename_write,
filename_read, filename_read,
uid_channel_var, uid_channel_var,
recipients)) { recipients,
beep_id)) {
ast_module_unref(ast_module_info->self); ast_module_unref(ast_module_info->self);
} }
@ -1084,6 +1114,7 @@ static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)
struct ast_datastore *datastore = NULL; struct ast_datastore *datastore = NULL;
char *parse = ""; char *parse = "";
struct mixmonitor_ds *mixmonitor_ds; struct mixmonitor_ds *mixmonitor_ds;
const char *beep_id = NULL;
AST_DECLARE_APP_ARGS(args, AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(mixmonid); AST_APP_ARG(mixmonid);
@ -1123,6 +1154,10 @@ static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)
mixmonitor_ds->audiohook = NULL; mixmonitor_ds->audiohook = NULL;
} }
if (!ast_strlen_zero(mixmonitor_ds->beep_id)) {
beep_id = ast_strdupa(mixmonitor_ds->beep_id);
}
ast_mutex_unlock(&mixmonitor_ds->lock); ast_mutex_unlock(&mixmonitor_ds->lock);
/* Remove the datastore so the monitor thread can exit */ /* Remove the datastore so the monitor thread can exit */
@ -1131,6 +1166,10 @@ static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)
} }
ast_channel_unlock(chan); ast_channel_unlock(chan);
if (!ast_strlen_zero(beep_id)) {
ast_beep_stop(chan, beep_id);
}
return 0; return 0;
} }

@ -6562,13 +6562,13 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
} }
ast_channel_unlock(qe->chan); ast_channel_unlock(qe->chan);
if (monitorfilename) { if (monitorfilename) {
ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT); ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT, NULL);
} else if (qe->chan) { } else if (qe->chan) {
ast_monitor_start(which, qe->parent->monfmt, ast_channel_uniqueid(qe->chan), 1, X_REC_IN | X_REC_OUT); ast_monitor_start(which, qe->parent->monfmt, ast_channel_uniqueid(qe->chan), 1, X_REC_IN | X_REC_OUT, NULL);
} else { } else {
/* Last ditch effort -- no channel, make up something */ /* Last ditch effort -- no channel, make up something */
snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random()); snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT); ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT, NULL);
} }
if (!ast_strlen_zero(monexec)) { if (!ast_strlen_zero(monexec)) {
ast_monitor_setjoinfiles(which, 1); ast_monitor_setjoinfiles(which, 1);

@ -196,7 +196,7 @@ static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct
ast_verb(3, "AutoMonitor used to record call. Filename: %s\n", touch_filename); ast_verb(3, "AutoMonitor used to record call. Filename: %s\n", touch_filename);
if (ast_monitor_start(peer_chan, touch_format, touch_filename, 1, X_REC_IN | X_REC_OUT)) { if (ast_monitor_start(peer_chan, touch_format, touch_filename, 1, X_REC_IN | X_REC_OUT, NULL)) {
ast_verb(3, "automon feature was tried by '%s' but monitor failed to start.\n", ast_verb(3, "automon feature was tried by '%s' but monitor failed to start.\n",
ast_channel_name(bridge_channel->chan)); ast_channel_name(bridge_channel->chan));
return; return;

@ -42,6 +42,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/pbx.h" #include "asterisk/pbx.h"
#include "asterisk/app.h" #include "asterisk/app.h"
#include "asterisk/audiohook.h" #include "asterisk/audiohook.h"
#define AST_API_MODULE
#include "asterisk/beep.h"
/*** DOCUMENTATION /*** DOCUMENTATION
<function name="PERIODIC_HOOK" language="en_US"> <function name="PERIODIC_HOOK" language="en_US">
@ -93,6 +95,8 @@ static const char context_name[] = "__func_periodic_hook_context__";
static const char exten_name[] = "hook"; static const char exten_name[] = "hook";
static const char full_exten_name[] = "hook@__func_periodic_hook_context__"; static const char full_exten_name[] = "hook@__func_periodic_hook_context__";
static const char beep_exten[] = "beep";
/*! /*!
* \brief Last used hook ID * \brief Last used hook ID
* *
@ -485,9 +489,35 @@ static int load_module(void)
ast_add_extension(context_name, 1, exten_name, 6, "", "", ast_add_extension(context_name, 1, exten_name, 6, "", "",
"ChanSpy", "${ChannelToSpy},qEB", NULL, AST_MODULE); "ChanSpy", "${ChannelToSpy},qEB", NULL, AST_MODULE);
res = ast_add_extension(context_name, 1, beep_exten, 1, "", "",
"Answer", "", NULL, AST_MODULE);
res |= ast_add_extension(context_name, 1, beep_exten, 2, "", "",
"Playback", "beep", NULL, AST_MODULE);
res = ast_custom_function_register_escalating(&hook_function, AST_CFE_BOTH); res = ast_custom_function_register_escalating(&hook_function, AST_CFE_BOTH);
return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
} }
int AST_OPTIONAL_API_NAME(ast_beep_start)(struct ast_channel *chan,
unsigned int interval, char *beep_id, size_t len)
{
char args[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 32];
snprintf(args, sizeof(args), "%s,%s,%u",
context_name, beep_exten, interval);
if (hook_read(chan, NULL, args, beep_id, len)) {
ast_log(LOG_WARNING, "Failed to enable periodic beep.\n");
return -1;
}
return 0;
}
int AST_OPTIONAL_API_NAME(ast_beep_stop)(struct ast_channel *chan, const char *beep_id)
{
return hook_write(chan, NULL, (char *) beep_id, "off");
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Periodic dialplan hooks."); AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Periodic dialplan hooks.");

@ -0,0 +1,45 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2014, Russell Bryant
*
* Russell Bryant <russell@russellbryant.net>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*!
* \file
* \brief Periodic beeps into the audio of a call
*/
#ifndef _ASTERISK_BEEP_H
#define _ASTERISK_BEEP_H
#include "asterisk/optional_api.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
AST_OPTIONAL_API(int, ast_beep_start,
(struct ast_channel *chan, unsigned int interval, char *beep_id, size_t len),
{ return -1; });
AST_OPTIONAL_API(int, ast_beep_stop,
(struct ast_channel *chan, const char *beep_id),
{ return -1; });
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
#endif /* _ASTERISK_BEEP_H */

@ -43,6 +43,7 @@ struct ast_channel_monitor {
char read_filename[FILENAME_MAX]; char read_filename[FILENAME_MAX];
char write_filename[FILENAME_MAX]; char write_filename[FILENAME_MAX];
char filename_base[FILENAME_MAX]; char filename_base[FILENAME_MAX];
char beep_id[64];
int filename_changed; int filename_changed;
char *format; char *format;
int joinfiles; int joinfiles;
@ -53,7 +54,8 @@ struct ast_channel_monitor {
/* Start monitoring a channel */ /* Start monitoring a channel */
AST_OPTIONAL_API(int, ast_monitor_start, AST_OPTIONAL_API(int, ast_monitor_start,
(struct ast_channel *chan, const char *format_spec, (struct ast_channel *chan, const char *format_spec,
const char *fname_base, int need_lock, int stream_action), const char *fname_base, int need_lock, int stream_action,
const char *beep_id),
{ return -1; }); { return -1; });
/* Stop monitoring a channel */ /* Stop monitoring a channel */

@ -50,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/utils.h" #include "asterisk/utils.h"
#include "asterisk/config.h" #include "asterisk/config.h"
#include "asterisk/options.h" #include "asterisk/options.h"
#include "asterisk/beep.h"
/*** DOCUMENTATION /*** DOCUMENTATION
<application name="Monitor" language="en_US"> <application name="Monitor" language="en_US">
@ -84,6 +85,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<option name="b"> <option name="b">
<para>Don't begin recording unless a call is bridged to another channel.</para> <para>Don't begin recording unless a call is bridged to another channel.</para>
</option> </option>
<option name="B">
<para>Play a periodic beep while this call is being recorded.</para>
<argument name="interval"><para>Interval, in seconds. Default is 15.</para></argument>
</option>
<option name="i"> <option name="i">
<para>Skip recording of input stream (disables <literal>m</literal> option).</para> <para>Skip recording of input stream (disables <literal>m</literal> option).</para>
</option> </option>
@ -290,7 +295,8 @@ static int ast_monitor_set_state(struct ast_channel *chan, int state)
* \retval -1 on failure * \retval -1 on failure
*/ */
int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const char *format_spec, int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const char *format_spec,
const char *fname_base, int need_lock, int stream_action) const char *fname_base, int need_lock, int stream_action,
const char *beep_id)
{ {
int res = 0; int res = 0;
RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
@ -309,6 +315,10 @@ int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const cha
return -1; return -1;
} }
if (!ast_strlen_zero(beep_id)) {
ast_copy_string(monitor->beep_id, beep_id, sizeof(monitor->beep_id));
}
/* Determine file names */ /* Determine file names */
if (!ast_strlen_zero(fname_base)) { if (!ast_strlen_zero(fname_base)) {
int directory = strchr(fname_base, '/') ? 1 : 0; int directory = strchr(fname_base, '/') ? 1 : 0;
@ -512,6 +522,10 @@ int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_l
ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp); ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
} }
if (!ast_strlen_zero(ast_channel_monitor(chan)->beep_id)) {
ast_beep_stop(chan, ast_channel_monitor(chan)->beep_id);
}
ast_free(ast_channel_monitor(chan)->format); ast_free(ast_channel_monitor(chan)->format);
ast_free(ast_channel_monitor(chan)); ast_free(ast_channel_monitor(chan));
ast_channel_monitor_set(chan, NULL); ast_channel_monitor_set(chan, NULL);
@ -644,6 +658,12 @@ enum {
MON_FLAG_MIX = (1 << 1), MON_FLAG_MIX = (1 << 1),
MON_FLAG_DROP_IN = (1 << 2), MON_FLAG_DROP_IN = (1 << 2),
MON_FLAG_DROP_OUT = (1 << 3), MON_FLAG_DROP_OUT = (1 << 3),
MON_FLAG_BEEP = (1 << 4),
};
enum {
OPT_ARG_BEEP_INTERVAL,
OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
}; };
AST_APP_OPTIONS(monitor_opts, { AST_APP_OPTIONS(monitor_opts, {
@ -651,6 +671,7 @@ AST_APP_OPTIONS(monitor_opts, {
AST_APP_OPTION('m', MON_FLAG_MIX), AST_APP_OPTION('m', MON_FLAG_MIX),
AST_APP_OPTION('i', MON_FLAG_DROP_IN), AST_APP_OPTION('i', MON_FLAG_DROP_IN),
AST_APP_OPTION('o', MON_FLAG_DROP_OUT), AST_APP_OPTION('o', MON_FLAG_DROP_OUT),
AST_APP_OPTION_ARG('B', MON_FLAG_BEEP, OPT_ARG_BEEP_INTERVAL),
}); });
/*! /*!
@ -672,6 +693,8 @@ static int start_monitor_exec(struct ast_channel *chan, const char *data)
int res = 0; int res = 0;
char *parse; char *parse;
struct ast_flags flags = { 0 }; struct ast_flags flags = { 0 };
char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
char beep_id[64] = "";
AST_DECLARE_APP_ARGS(args, AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(format); AST_APP_ARG(format);
AST_APP_ARG(fname_base); AST_APP_ARG(fname_base);
@ -688,7 +711,7 @@ static int start_monitor_exec(struct ast_channel *chan, const char *data)
AST_STANDARD_APP_ARGS(args, parse); AST_STANDARD_APP_ARGS(args, parse);
if (!ast_strlen_zero(args.options)) { if (!ast_strlen_zero(args.options)) {
ast_app_parse_options(monitor_opts, &flags, NULL, args.options); ast_app_parse_options(monitor_opts, &flags, opts, args.options);
if (ast_test_flag(&flags, MON_FLAG_MIX)) { if (ast_test_flag(&flags, MON_FLAG_MIX)) {
stream_action |= X_JOIN; stream_action |= X_JOIN;
@ -699,6 +722,20 @@ static int start_monitor_exec(struct ast_channel *chan, const char *data)
if (ast_test_flag(&flags, MON_FLAG_DROP_OUT)) { if (ast_test_flag(&flags, MON_FLAG_DROP_OUT)) {
stream_action &= ~X_REC_OUT; stream_action &= ~X_REC_OUT;
} }
if (ast_test_flag(&flags, MON_FLAG_BEEP)) {
const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
unsigned int interval = 15;
if (sscanf(interval_str, "%30u", &interval) != 1) {
ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
interval_str, interval);
}
if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
return -1;
}
}
} }
arg = strchr(args.format, ':'); arg = strchr(args.format, ':');
@ -731,7 +768,7 @@ static int start_monitor_exec(struct ast_channel *chan, const char *data)
return 0; return 0;
} }
res = ast_monitor_start(chan, args.format, args.fname_base, 1, stream_action); res = ast_monitor_start(chan, args.format, args.fname_base, 1, stream_action, beep_id);
if (res < 0) if (res < 0)
res = ast_monitor_change_fname(chan, args.fname_base, 1); res = ast_monitor_change_fname(chan, args.fname_base, 1);
@ -790,7 +827,7 @@ static int start_monitor_action(struct mansession *s, const struct message *m)
} }
} }
if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT)) { if (ast_monitor_start(c, format, fname, 1, X_REC_IN | X_REC_OUT, NULL)) {
if (ast_monitor_change_fname(c, fname, 1)) { if (ast_monitor_change_fname(c, fname, 1)) {
astman_send_error(s, m, "Could not start monitoring channel"); astman_send_error(s, m, "Could not start monitoring channel");
c = ast_channel_unref(c); c = ast_channel_unref(c);

Loading…
Cancel
Save