]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
app_mixmonitor: Add 'D' option for dual-channel audio.
authorBen Ford <bford@digium.com>
Mon, 28 Oct 2024 19:06:29 +0000 (14:06 -0500)
committerAsterisk Development Team <asteriskteam@digium.com>
Thu, 14 Nov 2024 20:01:34 +0000 (20:01 +0000)
Adds the 'D' option to app_mixmonitor that interleaves the input and
output frames of the channel being recorded in the monitor output frame.
This allows for two streams in the recording: the transmitted audio and
the received audio. The 't' and 'r' options are compatible with this.

Fixes: #945
UserNote: The MixMonitor application now has a new 'D' option which
interleaves the recorded audio in the output frames. This allows for
stereo recording output with one channel being the transmitted audio and
the other being the received audio. The 't' and 't' options are
compatible with this.

(cherry picked from commit 8273eefd87271dd0b3ce3483766e5defd2d96f63)

apps/app_mixmonitor.c

index 869d5537cb993461b5ddfe06cf1a72e33cc5587c..41257f826a9c4fea982ad8c48e9ceac282d368e6 100644 (file)
                                                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
@@ -414,6 +419,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 {
@@ -443,6 +449,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),
@@ -792,6 +799,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;