<p>Kevin Harwell <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/16339">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  George Joseph: Looks good to me, approved
  Kevin Harwell: Approved for Submit

</div><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, 240 insertions(+), 0 deletions(-)<br><br></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..01756d9</span><br><span>--- /dev/null</span><br><span>+++ b/funcs/func_scramble.c</span><br><span>@@ -0,0 +1,235 @@</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, or <literal>both</literal></span><br><span style="color: hsl(120, 100%, 40%);">+                              for both directions. <literal>remove</literal></span><br><span style="color: hsl(120, 100%, 40%);">+                            will remove an existing scrambler.</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%);">+                   <para>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 obfuscates audio on a channel</span><br><span style="color: hsl(120, 100%, 40%);">+                        to render it unintelligible, as a privacy enhancement.</para></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 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%);">+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%);">+/* 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%);">+</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%);">+</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%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Scramble 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 tx = 1, rx = 1;</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%);">+ if (!strcasecmp(args.direction, "remove")) {</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%);">+     if (!strcasecmp(args.direction, "tx")) {</span><br><span style="color: hsl(120, 100%, 40%);">+            tx = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+               rx = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (!strcasecmp(args.direction, "rx")) {</span><br><span style="color: hsl(120, 100%, 40%);">+             rx = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+               tx = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (strcasecmp(args.direction, "both")) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "Direction must be either RX, TX, both, or remove\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%);">+     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%);">+         /* 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%);">+             }</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%);">+             datastore->data = ni;</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_audiohook_attach(chan, &ni->audiohook);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</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%);">+     ni->tx = tx;</span><br><span style="color: hsl(120, 100%, 40%);">+       ni->rx = rx;</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_channel_unlock(chan);</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><div style="white-space:pre-wrap"></div><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/16339">change 16339</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/+/16339"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 19 </div>
<div style="display:none"> Gerrit-Change-Id: I01020769d91060a1f56a708eb405f87648d1a67e </div>
<div style="display:none"> Gerrit-Change-Number: 16339 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: N A <mail@interlinked.x10host.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>