diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c
index 82dc259984..50de99d603 100644
--- a/apps/app_mixmonitor.c
+++ b/apps/app_mixmonitor.c
@@ -158,6 +158,13 @@
separated by commas eg. m(1111@default,2222@default,...). Folders can be optionally specified using
the syntax: mailbox@context/folder
+
@@ -396,6 +403,8 @@
#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
+#define MIN_SKIP_SECONDS 1
+
static const char * const app = "MixMonitor";
static const char * const stop_app = "StopMixMonitor";
@@ -435,6 +444,9 @@ struct mixmonitor {
);
int call_priority;
+ /* Number of seconds (can be fractional) to skip at the start of recording */
+ double skip_seconds;
+
/* FUTURE DEVELOPMENT NOTICE
* recipient_list will need locks if we make it editable after the monitor is started */
AST_LIST_HEAD_NOLOCK(, vm_recipient) recipient_list;
@@ -459,6 +471,7 @@ enum mixmonitor_flags {
MUXFLAG_AUTO_DELETE = (1 << 16),
MUXFLAG_REAL_CALLERID = (1 << 17),
MUXFLAG_INTERLEAVED = (1 << 18),
+ MUXFLAG_SKIP = (1 << 19),
};
enum mixmonitor_args {
@@ -472,6 +485,7 @@ enum mixmonitor_args {
OPT_ARG_BEEP_INTERVAL,
OPT_ARG_DEPRECATED_RWSYNC,
OPT_ARG_NO_RWSYNC,
+ OPT_ARG_SKIP,
OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
};
@@ -493,6 +507,7 @@ AST_APP_OPTIONS(mixmonitor_opts, {
AST_APP_OPTION_ARG('m', MUXFLAG_VMRECIPIENTS, OPT_ARG_VMRECIPIENTS),
AST_APP_OPTION_ARG('S', MUXFLAG_DEPRECATED_RWSYNC, OPT_ARG_DEPRECATED_RWSYNC),
AST_APP_OPTION_ARG('n', MUXFLAG_NO_RWSYNC, OPT_ARG_NO_RWSYNC),
+ AST_APP_OPTION_ARG('s', MUXFLAG_SKIP, OPT_ARG_SKIP),
});
struct mixmonitor_ds {
@@ -777,6 +792,8 @@ static void *mixmonitor_thread(void *obj)
int errflag = 0;
struct ast_format *format_slin;
+ struct timeval skip_start = ast_tvnow();
+
/* Keep callid association before any log messages */
if (mixmonitor->callid) {
ast_callid_threadassoc_add(mixmonitor->callid);
@@ -797,6 +814,11 @@ static void *mixmonitor_thread(void *obj)
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
+ if (mixmonitor->skip_seconds > 0.0) {
+ ast_debug(3, "%s skipping initial %.3f seconds\n",
+ mixmonitor->name, mixmonitor->skip_seconds);
+ }
+
/* The audiohook must enter and exit the loop locked */
ast_audiohook_lock(&mixmonitor->audiohook);
while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
@@ -822,6 +844,22 @@ static void *mixmonitor_thread(void *obj)
|| mixmonitor_autochan_is_bridged(mixmonitor->autochan)) {
ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
+ /* Skip writing audio for the first N seconds */
+ if (mixmonitor->skip_seconds > 0.0) {
+ struct timeval now = ast_tvnow();
+ double elapsed = ast_tvdiff_ms(now, skip_start) / 1000.0;
+
+ if (elapsed < mixmonitor->skip_seconds) {
+ ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
+ /* Skip this frame and continue */
+ goto frame_cleanup;
+ } else {
+ ast_debug(3, "%s skip period %.3f seconds elapsed; starting to write audio\n",
+ mixmonitor->name, mixmonitor->skip_seconds);
+ mixmonitor->skip_seconds = 0.0;
+ }
+ }
+
/* Write out the frame(s) */
if ((*fs_read) && (fr_read)) {
struct ast_frame *cur;
@@ -888,6 +926,8 @@ static void *mixmonitor_thread(void *obj)
}
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}
+
+frame_cleanup:
/* All done! free it. */
if (fr) {
ast_frame_free(fr, 0);
@@ -1043,7 +1083,7 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
unsigned int flags, int readvol, int writevol,
const char *post_process, const char *filename_write,
char *filename_read, const char *uid_channel_var,
- const char *recipients, const char *beep_id)
+ const char *recipients, const char *beep_id, double skip_seconds)
{
pthread_t thread;
struct mixmonitor *mixmonitor;
@@ -1085,6 +1125,7 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
/* Copy over flags and channel name */
mixmonitor->flags = flags;
+ mixmonitor->skip_seconds = skip_seconds;
if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
mixmonitor_free(mixmonitor);
return -1;
@@ -1241,6 +1282,7 @@ static char *filename_parse(char *filename, char *buffer, size_t len)
static int mixmonitor_exec(struct ast_channel *chan, const char *data)
{
int x, readvol = 0, writevol = 0;
+ double skip_seconds = 0.0;
char *filename_read = NULL;
char *filename_write = NULL;
char filename_buffer[1024] = "";
@@ -1340,6 +1382,22 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
return -1;
}
}
+
+ if (ast_test_flag(&flags, MUXFLAG_SKIP)) {
+ if (ast_strlen_zero(opts[OPT_ARG_SKIP])) {
+ ast_log(LOG_WARNING, "No skip value provided for the 's' (skip) option; skipping will be ignored as no default exists.\n");
+ } else {
+ char *endptr = NULL;
+ double val = strtod(opts[OPT_ARG_SKIP], &endptr);
+ if (endptr == opts[OPT_ARG_SKIP] || *endptr != '\0') {
+ ast_log(LOG_WARNING, "Skip value '%s' is not a valid number; ignoring skip.\n", opts[OPT_ARG_SKIP]);
+ } else if (val < (double) MIN_SKIP_SECONDS) {
+ ast_log(LOG_WARNING, "Skip value %.3f is below minimum %d; ignoring skip.\n", val, MIN_SKIP_SECONDS);
+ } else {
+ skip_seconds = val;
+ }
+ }
+ }
}
/* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
@@ -1367,7 +1425,8 @@ static int mixmonitor_exec(struct ast_channel *chan, const char *data)
filename_read,
uid_channel_var,
recipients,
- beep_id)) {
+ beep_id,
+ skip_seconds)) {
ast_module_unref(ast_module_info->self);
}