diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c
index c31aaea649..a192fc362c 100644
--- a/apps/app_mixmonitor.c
+++ b/apps/app_mixmonitor.c
@@ -127,6 +127,11 @@
Like with the basic filename argument, if an absolute path isn't given, it will create
the file in the configured monitoring directory.
+
+ Interleave the audio coming from the channel and the audio coming to the channel in
+ the output audio as a dual channel stream, rather than mix it.
+ Use .raw as the extension.
+
When the r or t option is
used, MixMonitor will insert silence into the specified files to maintain
@@ -418,6 +423,7 @@ enum mixmonitor_flags {
MUXFLAG_NO_RWSYNC = (1 << 15),
MUXFLAG_AUTO_DELETE = (1 << 16),
MUXFLAG_REAL_CALLERID = (1 << 17),
+ MUXFLAG_INTERLEAVED = (1 << 18),
};
enum mixmonitor_args {
@@ -447,6 +453,7 @@ AST_APP_OPTIONS(mixmonitor_opts, {
AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
AST_APP_OPTION_ARG('r', MUXFLAG_READ, OPT_ARG_READNAME),
AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),
+ AST_APP_OPTION('D', MUXFLAG_INTERLEAVED),
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_DEPRECATED_RWSYNC, OPT_ARG_DEPRECATED_RWSYNC),
@@ -797,6 +804,46 @@ static void *mixmonitor_thread(void *obj)
}
}
+ if (ast_test_flag(mixmonitor, MUXFLAG_INTERLEAVED)) {
+ /* The 'D' option is set, so mix the frame as an interleaved dual channel frame */
+ int i;
+ short read_buf[SAMPLES_PER_FRAME];
+ short write_buf[SAMPLES_PER_FRAME];
+ short stereo_buf[SAMPLES_PER_FRAME * 2];
+ struct ast_frame stereo_frame = {
+ .frametype = AST_FRAME_VOICE,
+ .datalen = sizeof(stereo_buf),
+ .samples = SAMPLES_PER_FRAME,
+ };
+
+ if (fr) {
+ ast_frame_free(fr, 0);
+ fr = NULL;
+ }
+
+ if (fr_read) {
+ memcpy(read_buf, fr_read->data.ptr, sizeof(read_buf));
+ } else {
+ memset(read_buf, 0, sizeof(read_buf));
+ }
+
+ if (fr_write) {
+ memcpy(write_buf, fr_write->data.ptr, sizeof(write_buf));
+ } else {
+ memset(write_buf, 0, sizeof(write_buf));
+ }
+
+ for (i = 0; i < SAMPLES_PER_FRAME; i++) {
+ stereo_buf[i * 2] = read_buf[i];
+ stereo_buf[i * 2 + 1] = write_buf[i];
+ }
+
+ stereo_frame.data.ptr = stereo_buf;
+ stereo_frame.subclass.format = ast_format_cache_get_slin_by_rate(SAMPLES_PER_FRAME);
+
+ fr = ast_frdup(&stereo_frame);
+ }
+
if ((*fs) && (fr)) {
struct ast_frame *cur;