<p>Jenkins2 <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/6675">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  Richard Mudgett: Looks good to me, approved
  Jenkins2: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">ari/bridge: Add mute, dtmf suppression controls<br><br>Add bridge_features structure to bridge creation.  Specifically, this<br>implements mute and DTMF suppression, but others should be able to be<br>easily added to the same structure.<br><br>ASTERISK-27322 #close<br>Reported by: Darren Sessions<br>Sponsored by: AVOXI<br><br>Change-Id: Id4002adfb65c9a8027ee9e1a5f477e0f01cf9d61<br>---<br>M include/asterisk/stasis_app.h<br>M res/ari/resource_bridges.c<br>M res/ari/resource_bridges.h<br>M res/res_ari_bridges.c<br>M res/stasis/control.c<br>M rest-api/api-docs/bridges.json<br>6 files changed, 112 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h<br>index ca5c251..8ef2bda 100644<br>--- a/include/asterisk/stasis_app.h<br>+++ b/include/asterisk/stasis_app.h<br>@@ -793,6 +793,38 @@<br>     struct stasis_app_control *control, struct ast_bridge *bridge);<br> <br> /*!<br>+ * \brief Initialize bridge features into a channel control<br>+ *<br>+ * \note Bridge features on a control are destroyed after each bridge session,<br>+ *       so new features need to be initialized before each bridge add.<br>+ *<br>+ * \param control Control in which to store the features<br>+ *<br>+ * \return non-zero on failure<br>+ * \return zero on success<br>+ */<br>+int stasis_app_control_bridge_features_init(<br>+       struct stasis_app_control *control);<br>+<br>+/*!<br>+ * \brief Set whether DTMF from the channel is absorbed instead of passing through to the bridge<br>+ *<br>+ * \param control Control whose channel should have its DTMF absorbed when bridged<br>+ * \param absorb Whether DTMF should be absorbed (1) instead of passed through (0).<br>+ */<br>+void stasis_app_control_absorb_dtmf_in_bridge(<br>+      struct stasis_app_control *control, int absorb);<br>+<br>+/*!<br>+ * \brief Set whether audio from the channel is muted instead of passing through to the bridge<br>+ *<br>+ * \param control Control whose channel should have its audio muted when bridged<br>+ * \param mute Whether audio should be muted (1) instead of passed through (0).<br>+ */<br>+void stasis_app_control_mute_in_bridge(<br>+ struct stasis_app_control *control, int mute);<br>+<br>+/*!<br>  * \since 12<br>  * \brief Gets the bridge currently associated with a control object.<br>  *<br>diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c<br>index f243086..aab78ce 100644<br>--- a/res/ari/resource_bridges.c<br>+++ b/res/ari/resource_bridges.c<br>@@ -218,6 +218,12 @@<br>                            return;<br>                       }<br>             }<br>+<br>+         /* Apply bridge features to each of the channel controls */<br>+          if (!stasis_app_control_bridge_features_init(list->controls[i])) {<br>+                        stasis_app_control_absorb_dtmf_in_bridge(list->controls[i], args->absorb_dtmf);<br>+                        stasis_app_control_mute_in_bridge(list->controls[i], args->mute);<br>+              }<br>     }<br> <br>  for (i = 0; i < list->count; ++i) {<br>diff --git a/res/ari/resource_bridges.h b/res/ari/resource_bridges.h<br>index e75d8e0..72dba1e 100644<br>--- a/res/ari/resource_bridges.h<br>+++ b/res/ari/resource_bridges.h<br>@@ -150,6 +150,10 @@<br>      char *channel_parse;<br>  /*! Channel's role in the bridge */<br>       const char *role;<br>+    /*! Absorb DTMF coming from this channel, preventing it to pass through to the bridge */<br>+     int absorb_dtmf;<br>+     /*! Mute audio from this channel, preventing it to pass through to the bridge */<br>+     int mute;<br> };<br> /*!<br>  * \brief Body parsing function for /bridges/{bridgeId}/addChannel.<br>diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c<br>index 65bf7ed..35fd3bd 100644<br>--- a/res/res_ari_bridges.c<br>+++ b/res/res_ari_bridges.c<br>@@ -430,6 +430,14 @@<br>         if (field) {<br>          args->role = ast_json_string_get(field);<br>   }<br>+    field = ast_json_object_get(body, "absorbDTMF");<br>+   if (field) {<br>+         args->absorb_dtmf = ast_json_is_true(field);<br>+      }<br>+    field = ast_json_object_get(body, "mute");<br>+ if (field) {<br>+         args->mute = ast_json_is_true(field);<br>+     }<br>     return 0;<br> }<br> <br>@@ -499,6 +507,12 @@<br>                if (strcmp(i->name, "role") == 0) {<br>                      args.role = (i->value);<br>            } else<br>+               if (strcmp(i->name, "absorbDTMF") == 0) {<br>+                       args.absorb_dtmf = ast_true(i->value);<br>+            } else<br>+               if (strcmp(i->name, "mute") == 0) {<br>+                     args.mute = ast_true(i->value);<br>+           } else<br>                {}<br>    }<br>     for (i = path_vars; i; i = i->next) {<br>diff --git a/res/stasis/control.c b/res/stasis/control.c<br>index 01c04df..dc005a1 100644<br>--- a/res/stasis/control.c<br>+++ b/res/stasis/control.c<br>@@ -35,6 +35,7 @@<br> #include "asterisk/bridge.h"<br> #include "asterisk/bridge_after.h"<br> #include "asterisk/bridge_basic.h"<br>+#include "asterisk/bridge_features.h"<br> #include "asterisk/frame.h"<br> #include "asterisk/pbx.h"<br> #include "asterisk/musiconhold.h"<br>@@ -61,6 +62,10 @@<br>          * When a channel is in a bridge, the bridge that it is in.<br>    */<br>   struct ast_bridge *bridge;<br>+   /*!<br>+   * Bridge features which should be applied to the channel when it enters the next bridge.  These only apply to the next bridge and will be emptied thereafter.<br>+        */<br>+  struct ast_bridge_features *bridge_features;<br>  /*!<br>    * Holding place for channel's PBX while imparted to a bridge.<br>     */<br>@@ -99,6 +104,8 @@<br>       ast_cond_destroy(&control->wait_cond);<br>         AST_LIST_HEAD_DESTROY(&control->add_rules);<br>    AST_LIST_HEAD_DESTROY(&control->remove_rules);<br>+        ast_bridge_features_destroy(control->bridge_features);<br>+<br> }<br> <br> struct stasis_app_control *control_create(struct ast_channel *channel, struct stasis_app *app)<br>@@ -1161,6 +1168,7 @@<br> int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap)<br> {<br>       int res;<br>+     struct ast_bridge_features *features;<br> <br>      if (!control || !bridge) {<br>            return -1;<br>@@ -1205,6 +1213,10 @@<br>            ast_channel_pbx_set(chan, NULL);<br>      }<br> <br>+ /* Pull bridge features from the control */<br>+  features = control->bridge_features;<br>+      control->bridge_features = NULL;<br>+<br>        ast_assert(stasis_app_get_bridge(control) == NULL);<br>   /* We need to set control->bridge here since bridge_after_cb may be run<br>     * before ast_bridge_impart returns.  bridge_after_cb gets a reason<br>@@ -1220,7 +1232,7 @@<br>    res = ast_bridge_impart(bridge,<br>               chan,<br>                 swap,<br>-                NULL, /* features */<br>+         features, /* features */<br>              AST_BRIDGE_IMPART_CHAN_DEPARTABLE);<br>   if (res != 0) {<br>               /* ast_bridge_impart failed before it could spawn the depart<br>@@ -1316,6 +1328,31 @@<br>  return ast_queue_control(control->channel, frame_type);<br> }<br> <br>+int stasis_app_control_bridge_features_init(<br>+     struct stasis_app_control *control)<br>+{<br>+      struct ast_bridge_features *features;<br>+<br>+     features = ast_bridge_features_new();<br>+        if (!features) {<br>+             return 1;<br>+    }<br>+    control->bridge_features = features;<br>+      return 0;<br>+}<br>+<br>+void stasis_app_control_absorb_dtmf_in_bridge(<br>+    struct stasis_app_control *control, int absorb)<br>+{<br>+  control->bridge_features->dtmf_passthrough = !absorb;<br>+}<br>+<br>+void stasis_app_control_mute_in_bridge(<br>+ struct stasis_app_control *control, int mute)<br>+{<br>+    control->bridge_features->mute = mute;<br>+}<br>+<br> void control_flush_queue(struct stasis_app_control *control)<br> {<br>        struct ao2_iterator iter;<br>diff --git a/rest-api/api-docs/bridges.json b/rest-api/api-docs/bridges.json<br>index 877fdf8..cf8ee31 100644<br>--- a/rest-api/api-docs/bridges.json<br>+++ b/rest-api/api-docs/bridges.json<br>@@ -169,6 +169,24 @@<br>                                                      "required": false,<br>                                                  "allowMultiple": false,<br>                                                     "dataType": "string"<br>+                                             },<br>+                                           {<br>+                                                    "name": "absorbDTMF",<br>+                                                    "description": "Absorb DTMF coming from this channel, preventing it to pass through to the bridge",<br>+                                                      "paramType": "query",<br>+                                                    "required": false,<br>+                                                 "allowMultiple": false,<br>+                                                    "dataType": "boolean",<br>+                                                   "defaultValue": false<br>+                                              },<br>+                                           {<br>+                                                    "name": "mute",<br>+                                                  "description": "Mute audio from this channel, preventing it to pass through to the bridge",<br>+                                                      "paramType": "query",<br>+                                                    "required": false,<br>+                                                 "allowMultiple": false,<br>+                                                    "dataType": "boolean",<br>+                                                   "defaultValue": false<br>                                               }<br>                                     ],<br>                                    "errorResponses": [<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6675">change 6675</a>. To unsubscribe, 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/6675"/><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-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Id4002adfb65c9a8027ee9e1a5f477e0f01cf9d61 </div>
<div style="display:none"> Gerrit-Change-Number: 6675 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </div>
<div style="display:none"> Gerrit-Owner: Seán C. McCord <ulexus@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Richard Mudgett <rmudgett@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Seán C. McCord <ulexus@gmail.com> </div>