]> 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)
committerBen Ford <bford@digium.com>
Mon, 4 Nov 2024 15:07:36 +0000 (15:07 +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.

apps/app_mixmonitor.c

index c31aaea64974b02940784b3490b9d159510dbfed..a192fc362c35f93216246ff3af2154015262ab74 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
@@ -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;