diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c index 011b46a251..1788fe061f 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 + @@ -393,6 +400,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"; @@ -431,6 +440,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; @@ -455,6 +467,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 { @@ -468,6 +481,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 */ }; @@ -489,6 +503,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 { @@ -772,6 +787,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); @@ -792,6 +809,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) { @@ -817,6 +839,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; @@ -883,6 +921,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); @@ -1038,7 +1078,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; @@ -1080,6 +1120,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; @@ -1235,6 +1276,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] = ""; @@ -1334,6 +1376,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 */ @@ -1361,7 +1419,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); }