diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c
index 9f147768dd..ecb0830ed3 100644
--- a/apps/app_mixmonitor.c
+++ b/apps/app_mixmonitor.c
@@ -117,6 +117,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
Like with the basic filename argument, if an absolute path isn't given, it will create
the file in the configured monitoring directory.
+
+ When combined with the r or t
+ option, inserts silence when necessary to maintain synchronization between the receive
+ and transmit audio streams.
+
Stores the MixMonitor's ID on this channel variable.
@@ -349,7 +354,8 @@ enum mixmonitor_flags {
MUXFLAG_VMRECIPIENTS = (1 << 10),
MUXFLAG_BEEP = (1 << 11),
MUXFLAG_BEEP_START = (1 << 12),
- MUXFLAG_BEEP_STOP = (1 << 13)
+ MUXFLAG_BEEP_STOP = (1 << 13),
+ MUXFLAG_RWSYNC = (1 << 14),
};
enum mixmonitor_args {
@@ -361,6 +367,7 @@ enum mixmonitor_args {
OPT_ARG_UID,
OPT_ARG_VMRECIPIENTS,
OPT_ARG_BEEP_INTERVAL,
+ OPT_ARG_RWSYNC,
OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
};
@@ -377,6 +384,7 @@ AST_APP_OPTIONS(mixmonitor_opts, {
AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),
AST_APP_OPTION_ARG('i', MUXFLAG_UID, OPT_ARG_UID),
AST_APP_OPTION_ARG('m', MUXFLAG_VMRECIPIENTS, OPT_ARG_VMRECIPIENTS),
+ AST_APP_OPTION_ARG('S', MUXFLAG_RWSYNC, OPT_ARG_RWSYNC),
});
struct mixmonitor_ds {
@@ -967,6 +975,9 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
}
ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
+ if ((ast_test_flag(mixmonitor, MUXFLAG_RWSYNC))) {
+ ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_SUBSTITUTE_SILENCE);
+ }
if (readvol)
mixmonitor->audiohook.options.read_volume = readvol;
diff --git a/doc/CHANGES-staging/mixmonitor-s-option.txt b/doc/CHANGES-staging/mixmonitor-s-option.txt
new file mode 100644
index 0000000000..d08b86d3fc
--- /dev/null
+++ b/doc/CHANGES-staging/mixmonitor-s-option.txt
@@ -0,0 +1,7 @@
+Subject: app_mixmonitor
+
+An option 'S' has been added to MixMonitor. If used in combination with
+the r() and/or t() options, if a frame is available to write to one of
+those files but not the other, a frame of silence if written to the file
+that does not have an audio frame. This should prevent the two files
+from "drifting" when mixed after the fact.
diff --git a/include/asterisk/audiohook.h b/include/asterisk/audiohook.h
index cae8cc0711..1252e3655b 100644
--- a/include/asterisk/audiohook.h
+++ b/include/asterisk/audiohook.h
@@ -64,6 +64,8 @@ enum ast_audiohook_flags {
AST_AUDIOHOOK_MUTE_READ = (1 << 5), /*!< audiohook should be mute frames read */
AST_AUDIOHOOK_MUTE_WRITE = (1 << 6), /*!< audiohook should be mute frames written */
AST_AUDIOHOOK_COMPATIBLE = (1 << 7), /*!< is the audiohook native slin compatible */
+
+ AST_AUDIOHOOK_SUBSTITUTE_SILENCE = (1 << 8), /*!< Substitute silence for missing audio */
};
enum ast_audiohook_init_flags {
diff --git a/main/audiohook.c b/main/audiohook.c
index cb3c4bcb31..3feb114a2d 100644
--- a/main/audiohook.c
+++ b/main/audiohook.c
@@ -335,6 +335,17 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
frame.subclass.format = ast_format_cache_get_slin_by_rate(audiohook->hook_internal_samp_rate);
+ /* Should we substitute silence if one side lacks audio? */
+ if ((ast_test_flag(audiohook, AST_AUDIOHOOK_SUBSTITUTE_SILENCE))) {
+ if (read_reference && !read_buf && write_buf) {
+ read_buf = buf1;
+ memset(buf1, 0, sizeof(buf1));
+ } else if (write_reference && read_buf && !write_buf) {
+ write_buf = buf2;
+ memset(buf2, 0, sizeof(buf2));
+ }
+ }
+
/* Basically we figure out which buffer to use... and if mixing can be done here */
if (read_buf && read_reference) {
frame.data.ptr = read_buf;