mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-30 18:21:52 +00:00
app_mixmonitor: Add 's' (skip) option to delay recording.
The 's' (skip) option delays MixMonitor recording until the specified number of seconds
(can be fractional) have elapsed since MixMonitor was invoked.
No audio is written to the recording file during this time. If the call ends before this
period, no audio will be saved. This is useful for avoiding early audio such as
announcements, ringback tones, or other non-essential sounds.
UserNote: This change introduces a new 's(<seconds>)' (skip) option to the MixMonitor
application. Example:
MixMonitor(${UNIQUEID}.wav,s(3))
This skips recording for the first 3 seconds before writing audio to the file.
Existing MixMonitor behavior remains unchanged when the 's' option is not used.
This commit is contained in:
@@ -158,6 +158,13 @@
|
||||
separated by commas eg. m(1111@default,2222@default,...). Folders can be optionally specified using
|
||||
the syntax: mailbox@context/folder</para>
|
||||
</option>
|
||||
<option name="s">
|
||||
<argument name="seconds" required="true" />
|
||||
<para>Don't record until <replaceable>seconds</replaceable> (can be fractional) have elapsed since MixMonitor was invoked.
|
||||
No audio is written to the recording file during this time. If the call ends before this period,
|
||||
no audio will be saved. This can be useful to avoid recording announcements,
|
||||
ringback tones, or other non-essential early audio.</para>
|
||||
</option>
|
||||
</optionlist>
|
||||
</parameter>
|
||||
<parameter name="command">
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user