Like with the basic filename argument, if an absolute path isn't given, it will create
the file in the configured monitoring directory.</para>
</option>
+ <option name="D">
+ <para>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.</para>
+ <note><para>Use .raw as the extension.</para></note>
+ </option>
<option name="n">
<para>When the <replaceable>r</replaceable> or <replaceable>t</replaceable> option is
used, MixMonitor will insert silence into the specified files to maintain
MUXFLAG_NO_RWSYNC = (1 << 15),
MUXFLAG_AUTO_DELETE = (1 << 16),
MUXFLAG_REAL_CALLERID = (1 << 17),
+ MUXFLAG_INTERLEAVED = (1 << 18),
};
enum mixmonitor_args {
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),
}
}
+ 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;