<p>N A has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/16231">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">func_scramble: Audio scrambler function<br><br>Adds a function to scramble audio on a channel using<br>whole spectrum frequency inversion. This can be used<br>as a privacy enhancement with applications like<br>ChanSpy or other potentially sensitive audio.<br><br>ASTERISK-29542<br><br>Change-Id: I01020769d91060a1f56a708eb405f87648d1a67e<br>---<br>A doc/CHANGES-staging/func_scramble.txt<br>A funcs/func_scramble.c<br>2 files changed, 252 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/31/16231/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/doc/CHANGES-staging/func_scramble.txt b/doc/CHANGES-staging/func_scramble.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..4c1ffab</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/func_scramble.txt</span><br><span>@@ -0,0 +1,5 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: func_scramble</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Adds an audio scrambler function that may be used to</span><br><span style="color: hsl(120, 100%, 40%);">+distort voice audio on a channel as a privacy</span><br><span style="color: hsl(120, 100%, 40%);">+enhancement.</span><br><span>diff --git a/funcs/func_scramble.c b/funcs/func_scramble.c</span><br><span>new file mode 100644</span><br><span>index 0000000..03fd5df</span><br><span>--- /dev/null</span><br><span>+++ b/funcs/func_scramble.c</span><br><span>@@ -0,0 +1,247 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*
</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.
</span><br><span style="color: hsl(120, 100%, 40%);">+ *
</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2021, Naveen Albert
</span><br><span style="color: hsl(120, 100%, 40%);">+ *
</span><br><span style="color: hsl(120, 100%, 40%);">+ * Naveen Albert <asterisk@phreaknet.org>
</span><br><span style="color: hsl(120, 100%, 40%);">+ *
</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about
</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact
</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;
</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC
</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.
</span><br><span style="color: hsl(120, 100%, 40%);">+ *
</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of
</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file
</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.
</span><br><span style="color: hsl(120, 100%, 40%);">+ */
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file
</span><br><span style="color: hsl(120, 100%, 40%);">+ *
</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Frequency inverter
</span><br><span style="color: hsl(120, 100%, 40%);">+ *
</span><br><span style="color: hsl(120, 100%, 40%);">+ * \author Naveen Albert <asterisk@phreaknet.org>
</span><br><span style="color: hsl(120, 100%, 40%);">+ *
</span><br><span style="color: hsl(120, 100%, 40%);">+ * \ingroup functions
</span><br><span style="color: hsl(120, 100%, 40%);">+ *
</span><br><span style="color: hsl(120, 100%, 40%);">+ */
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+/*** MODULEINFO
</span><br><span style="color: hsl(120, 100%, 40%);">+      <support_level>extended</support_level>
</span><br><span style="color: hsl(120, 100%, 40%);">+ ***/
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+/*** DOCUMENTATION
</span><br><span style="color: hsl(120, 100%, 40%);">+      <function name="SCRAMBLE" language="en_US">
</span><br><span style="color: hsl(120, 100%, 40%);">+              <synopsis>
</span><br><span style="color: hsl(120, 100%, 40%);">+                      Scrambles audio on a channel.
</span><br><span style="color: hsl(120, 100%, 40%);">+              </synopsis>
</span><br><span style="color: hsl(120, 100%, 40%);">+              <syntax>
</span><br><span style="color: hsl(120, 100%, 40%);">+                      <parameter name="direction" required="false">
</span><br><span style="color: hsl(120, 100%, 40%);">+                              <para>Must be <literal>TX</literal> or <literal>RX</literal>
</span><br><span style="color: hsl(120, 100%, 40%);">+                              to limit to a specific direction.</para>
</span><br><span style="color: hsl(120, 100%, 40%);">+                      </parameter>
</span><br><span style="color: hsl(120, 100%, 40%);">+              </syntax>
</span><br><span style="color: hsl(120, 100%, 40%);">+              <description>
</span><br><span style="color: hsl(120, 100%, 40%);">+                      Scrambles audio on a channel using whole spectrum inversion.
</span><br><span style="color: hsl(120, 100%, 40%);">+                      This is not intended to be used for securely scrambling </span><br><span style="color: hsl(120, 100%, 40%);">+                      audio. It merely renders audio unintelligible on a channel
</span><br><span style="color: hsl(120, 100%, 40%);">+                      as a privacy enhancement.
</span><br><span style="color: hsl(120, 100%, 40%);">+              </description>
</span><br><span style="color: hsl(120, 100%, 40%);">+              <see-also>
</span><br><span style="color: hsl(120, 100%, 40%);">+                      <ref type="application">ChanSpy</ref>
</span><br><span style="color: hsl(120, 100%, 40%);">+              </see-also>
</span><br><span style="color: hsl(120, 100%, 40%);">+      </function>
</span><br><span style="color: hsl(120, 100%, 40%);">+ ***/
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/module.h"
</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/channel.h"
</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/pbx.h"
</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/utils.h"
</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/audiohook.h"
</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/app.h"
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h>
</span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h>
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+struct scramble_information {
</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_audiohook audiohook;
</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned short int tx;
</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned short int rx;
</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int flags;
</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned short int state;
</span><br><span style="color: hsl(120, 100%, 40%);">+};
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+enum scramble_flags {
</span><br><span style="color: hsl(120, 100%, 40%);">+      FLAG_TRANSMIT_DIR = (1 << 1),
</span><br><span style="color: hsl(120, 100%, 40%);">+      FLAG_RECEIVE_DIR = (1 << 2),
</span><br><span style="color: hsl(120, 100%, 40%);">+      FLAG_END_FILTER = (1 << 3),
</span><br><span style="color: hsl(120, 100%, 40%);">+};
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+static void destroy_callback(void *data)
</span><br><span style="color: hsl(120, 100%, 40%);">+{
</span><br><span style="color: hsl(120, 100%, 40%);">+      struct scramble_information *ni = data;
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Destroy the audiohook, and destroy ourselves */
</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_audiohook_lock(&ni->audiohook);
</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_audiohook_detach(&ni->audiohook);
</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_audiohook_unlock(&ni->audiohook);
</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_audiohook_destroy(&ni->audiohook);
</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_free(ni);
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      return;
</span><br><span style="color: hsl(120, 100%, 40%);">+}
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Static structure for datastore information */
</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct ast_datastore_info scramble_datastore = {
</span><br><span style="color: hsl(120, 100%, 40%);">+      .type = "scramble",
</span><br><span style="color: hsl(120, 100%, 40%);">+      .destroy = destroy_callback
</span><br><span style="color: hsl(120, 100%, 40%);">+};
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+/* return 0 if nothing detected, 1 if lack of tone, 2 if presence of tone */
</span><br><span style="color: hsl(120, 100%, 40%);">+/* modifies buffer pointed to by 'amp' with inverted values */
</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void freq_invert(short *amp, int samples)
</span><br><span style="color: hsl(120, 100%, 40%);">+{
</span><br><span style="color: hsl(120, 100%, 40%);">+      int i;
</span><br><span style="color: hsl(120, 100%, 40%);">+      /* invert every other sample by 1 */
</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < samples; i += 2) {
</span><br><span style="color: hsl(120, 100%, 40%);">+              amp[i] = -(amp[i]);
</span><br><span style="color: hsl(120, 100%, 40%);">+      }
</span><br><span style="color: hsl(120, 100%, 40%);">+}
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+static int scramble_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
</span><br><span style="color: hsl(120, 100%, 40%);">+{
</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_datastore *datastore = NULL;
</span><br><span style="color: hsl(120, 100%, 40%);">+      struct scramble_information *ni = NULL;
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
</span><br><span style="color: hsl(120, 100%, 40%);">+      if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0;
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Grab datastore which contains our gain information */
</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!(datastore = ast_channel_datastore_find(chan, &scramble_datastore, NULL)))
</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0;
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      if (frame->frametype == AST_FRAME_VOICE) { /* only invert voice frequencies */
</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Based on direction of frame, and confirm it is applicable */
</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!(direction == AST_AUDIOHOOK_DIRECTION_READ ? &ni->rx : &ni->tx))
</span><br><span style="color: hsl(120, 100%, 40%);">+                      return 0;
</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Notch the sample now */
</span><br><span style="color: hsl(120, 100%, 40%);">+              freq_invert(frame->data.ptr, frame->samples);
</span><br><span style="color: hsl(120, 100%, 40%);">+      }
</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;
</span><br><span style="color: hsl(120, 100%, 40%);">+}
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \internal \brief Disable scrambling on the channel */
</span><br><span style="color: hsl(120, 100%, 40%);">+static int remove_scrambler(struct ast_channel *chan)
</span><br><span style="color: hsl(120, 100%, 40%);">+{
</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_datastore *datastore = NULL;
</span><br><span style="color: hsl(120, 100%, 40%);">+      struct scramble_information *data;
</span><br><span style="color: hsl(120, 100%, 40%);">+      SCOPED_CHANNELLOCK(chan_lock, chan);
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      datastore = ast_channel_datastore_find(chan, &scramble_datastore, NULL);
</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!datastore) {
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(AST_LOG_WARNING, "Cannot remove SCRAMBLE from %s: SCRAMBLE not currently enabled\n",
</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_channel_name(chan));
</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;
</span><br><span style="color: hsl(120, 100%, 40%);">+      }
</span><br><span style="color: hsl(120, 100%, 40%);">+      data = datastore->data;
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ast_audiohook_remove(chan, &data->audiohook)) {
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(AST_LOG_WARNING, "Failed to remove SCRAMBLE audiohook from channel %s\n", ast_channel_name(chan));
</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;
</span><br><span style="color: hsl(120, 100%, 40%);">+      }
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ast_channel_datastore_remove(chan, datastore)) {
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(AST_LOG_WARNING, "Failed to remove SCRAMBLE datastore from channel %s\n",
</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_channel_name(chan));
</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;
</span><br><span style="color: hsl(120, 100%, 40%);">+      }
</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_datastore_free(datastore);
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;
</span><br><span style="color: hsl(120, 100%, 40%);">+}
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+static int scramble_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
</span><br><span style="color: hsl(120, 100%, 40%);">+{
</span><br><span style="color: hsl(120, 100%, 40%);">+      char *parse;
</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_datastore *datastore = NULL;
</span><br><span style="color: hsl(120, 100%, 40%);">+      struct scramble_information *ni = NULL;
</span><br><span style="color: hsl(120, 100%, 40%);">+      int is_new = 0;
</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_flags flags = { 0 };
</span><br><span style="color: hsl(120, 100%, 40%);">+      </span><br><span style="color: hsl(120, 100%, 40%);">+      AST_DECLARE_APP_ARGS(args,
</span><br><span style="color: hsl(120, 100%, 40%);">+              AST_APP_ARG(direction);
</span><br><span style="color: hsl(120, 100%, 40%);">+      );
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!chan) {
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;
</span><br><span style="color: hsl(120, 100%, 40%);">+      }
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      parse = ast_strdupa(value);
</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_STANDARD_APP_ARGS(args, parse);
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_channel_lock(chan);
</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!(datastore = ast_channel_datastore_find(chan, &scramble_datastore, NULL))) {
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_channel_unlock(chan);
</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Allocate a new datastore to hold the reference to this audiohook information */
</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!(datastore = ast_datastore_alloc(&scramble_datastore, NULL)))
</span><br><span style="color: hsl(120, 100%, 40%);">+                      return 0;
</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!(ni = ast_calloc(1, sizeof(*ni)))) {
</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_datastore_free(datastore);
</span><br><span style="color: hsl(120, 100%, 40%);">+                      return 0;
</span><br><span style="color: hsl(120, 100%, 40%);">+              }
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_audiohook_init(&ni->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Voice scrambler", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
</span><br><span style="color: hsl(120, 100%, 40%);">+              ni->audiohook.manipulate_callback = scramble_callback;
</span><br><span style="color: hsl(120, 100%, 40%);">+              is_new = 1;
</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_channel_unlock(chan);
</span><br><span style="color: hsl(120, 100%, 40%);">+              ni = datastore->data;
</span><br><span style="color: hsl(120, 100%, 40%);">+      }
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ast_test_flag(&flags, FLAG_END_FILTER)) {
</span><br><span style="color: hsl(120, 100%, 40%);">+              return remove_scrambler(chan);
</span><br><span style="color: hsl(120, 100%, 40%);">+      }
</span><br><span style="color: hsl(120, 100%, 40%);">+      </span><br><span style="color: hsl(120, 100%, 40%);">+      if (!strcasecmp(args.direction, "tx")) {
</span><br><span style="color: hsl(120, 100%, 40%);">+              ni->tx = 1;
</span><br><span style="color: hsl(120, 100%, 40%);">+              ni->rx = 1;
</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (!strcasecmp(args.direction, "rx")) {
</span><br><span style="color: hsl(120, 100%, 40%);">+              ni->rx = 1;
</span><br><span style="color: hsl(120, 100%, 40%);">+              ni->tx = 1;
</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {
</span><br><span style="color: hsl(120, 100%, 40%);">+              ni->tx = 1;
</span><br><span style="color: hsl(120, 100%, 40%);">+              ni->rx = 1;
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "Direction must be either RX or TX\n");
</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;
</span><br><span style="color: hsl(120, 100%, 40%);">+      }
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      if (is_new) {
</span><br><span style="color: hsl(120, 100%, 40%);">+              datastore->data = ni;
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_channel_lock(chan);
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_channel_datastore_add(chan, datastore);
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_channel_unlock(chan);
</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_audiohook_attach(chan, &ni->audiohook);
</span><br><span style="color: hsl(120, 100%, 40%);">+      }
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;
</span><br><span style="color: hsl(120, 100%, 40%);">+}
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_custom_function scramble_function = {
</span><br><span style="color: hsl(120, 100%, 40%);">+      .name = "SCRAMBLE",
</span><br><span style="color: hsl(120, 100%, 40%);">+      .write = scramble_write,
</span><br><span style="color: hsl(120, 100%, 40%);">+};
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+static int unload_module(void)
</span><br><span style="color: hsl(120, 100%, 40%);">+{
</span><br><span style="color: hsl(120, 100%, 40%);">+      return ast_custom_function_unregister(&scramble_function);
</span><br><span style="color: hsl(120, 100%, 40%);">+}
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+static int load_module(void)
</span><br><span style="color: hsl(120, 100%, 40%);">+{
</span><br><span style="color: hsl(120, 100%, 40%);">+      return ast_custom_function_register(&scramble_function);
</span><br><span style="color: hsl(120, 100%, 40%);">+}
</span><br><span style="color: hsl(120, 100%, 40%);">+
</span><br><span style="color: hsl(120, 100%, 40%);">+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Frequency inverting voice scrambler");
</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/16231">change 16231</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/16231"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I01020769d91060a1f56a708eb405f87648d1a67e </div>
<div style="display:none"> Gerrit-Change-Number: 16231 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: N A <mail@interlinked.x10host.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>