<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/10204">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Kevin Harwell: Looks good to me, but someone else must approve
Sean Bright: Looks good to me, but someone else must approve
George Joseph: Looks good to me, approved; Approved for Submit
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_remb_modifier: Add module for controlling REMB from CLI.<br><br>This adds a module which registers a CLI command that can set the<br>REMB bitrate value for REMB as it enters or exits Asterisk. This<br>allows you to ignore what Asterisk or a client produces and is<br>useful for demonstrations.<br><br>This does not generate REMB frames, however, but just modifies<br>them as they flow to or from a channel.<br><br>Change-Id: Ib089427c46a4a36d645cecfe02406adb38c17bec<br>---<br>A res/res_remb_modifier.c<br>1 file changed, 225 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/res/res_remb_modifier.c b/res/res_remb_modifier.c</span><br><span>new file mode 100644</span><br><span>index 0000000..1e79b83</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_remb_modifier.c</span><br><span>@@ -0,0 +1,225 @@</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) 2018, Digium, Inc.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Joshua Colp <jcolp@digium.com></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%);">+/*!</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 REMB Modifier Module</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \author Joshua Colp <jcolp@digium.com></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%);">+ <defaultenabled>no</defaultenabled></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/cli.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/framehook.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/rtp_engine.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct remb_values {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief The amount of bitrate to use for REMB received from the channel */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int receive_bitrate;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief The amount of bitrate to use for REMB sent to the channel */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int send_bitrate;</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 remb_values_free(void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(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%);">+static const struct ast_datastore_info remb_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .type = "REMB Values",</span><br><span style="color: hsl(120, 100%, 40%);">+ .destroy = remb_values_free,</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_frame *remb_hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_rtp_rtcp_feedback *feedback;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_datastore *remb_store;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct remb_values *remb_values;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!frame) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</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%);">+ switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AST_FRAMEHOOK_EVENT_READ:</span><br><span style="color: hsl(120, 100%, 40%);">+ case AST_FRAMEHOOK_EVENT_WRITE:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case AST_FRAMEHOOK_EVENT_ATTACHED:</span><br><span style="color: hsl(120, 100%, 40%);">+ case AST_FRAMEHOOK_EVENT_DETACHED:</span><br><span style="color: hsl(120, 100%, 40%);">+ return frame;</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%);">+ /* We only care about REMB frames, all others will be unmodified */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (frame->subclass.integer != AST_RTP_RTCP_PSFB) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return frame;</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%);">+ feedback = frame->data.ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (feedback->fmt != AST_RTP_RTCP_FMT_REMB) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return frame;</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%);">+ remb_store = ast_channel_datastore_find(chan, &remb_info, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!remb_store) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return frame;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ remb_values = remb_store->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If a bitrate override has been set apply it to the REMB Frame */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (event == AST_FRAMEHOOK_EVENT_READ && remb_values->receive_bitrate) {</span><br><span style="color: hsl(120, 100%, 40%);">+ feedback->remb.br_mantissa = remb_values->receive_bitrate;</span><br><span style="color: hsl(120, 100%, 40%);">+ feedback->remb.br_exp = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (event == AST_FRAMEHOOK_EVENT_WRITE && remb_values->send_bitrate) {</span><br><span style="color: hsl(120, 100%, 40%);">+ feedback->remb.br_mantissa = remb_values->send_bitrate;</span><br><span style="color: hsl(120, 100%, 40%);">+ feedback->remb.br_exp = 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%);">+ /* The mantissa only has 18 bits available, so while it exceeds them we bump</span><br><span style="color: hsl(120, 100%, 40%);">+ * up the exp.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ while (feedback->remb.br_mantissa > 0x3ffff) {</span><br><span style="color: hsl(120, 100%, 40%);">+ feedback->remb.br_mantissa = feedback->remb.br_mantissa >> 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ feedback->remb.br_exp++;</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 frame;</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 char *handle_remb_set(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_channel *chan;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int bitrate;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_datastore *remb_store;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct remb_values *remb_values;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_framehook_interface interface = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .version = AST_FRAMEHOOK_INTERFACE_VERSION,</span><br><span style="color: hsl(120, 100%, 40%);">+ .event_cb = remb_hook_event_cb,</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%);">+ switch(cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ e->command = "remb set {send|receive}";</span><br><span style="color: hsl(120, 100%, 40%);">+ e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+ "Usage: remb set {send|receive} <channel> <bitrate in bits>\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ " Set the REMB value which overwrites what we send or receive\n";</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_complete_channels(a->line, a->word, a->pos, a->n, 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%);">+ if (a->argc != 5) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SHOWUSAGE;</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 (sscanf(a->argv[4], "%30d", &bitrate) != 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "%s is not a valid bitrate in bits\n", a->argv[4]);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (strcasecmp(a->argv[2], "send") && strcasecmp(a->argv[2], "receive")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "%s is not a valid direction for REMB\n", a->argv[2]);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</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%);">+ chan = ast_channel_get_by_name(a->argv[3]);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</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_channel_lock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ remb_store = ast_channel_datastore_find(chan, &remb_info, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!remb_store) {</span><br><span style="color: hsl(120, 100%, 40%);">+ int framehook_id;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ framehook_id = ast_framehook_attach(chan, &interface);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (framehook_id < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "Could not attach framehook for modifying REMB\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unref(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</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%);">+ remb_values = ast_calloc(1, sizeof(*remb_values));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!remb_values) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "Could not create a place to store provided REMB value\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_framehook_detach(chan, framehook_id);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unref(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</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%);">+ remb_store = ast_datastore_alloc(&remb_info, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!remb_store) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "Could not create a place to store provided REMB value\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_framehook_detach(chan, framehook_id);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unref(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(remb_values);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</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%);">+ remb_store->data = remb_values;</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_datastore_add(chan, remb_store);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ remb_values = remb_store->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 (!strcasecmp(a->argv[2], "send")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ remb_values->send_bitrate = bitrate;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcasecmp(a->argv[2], "receive")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ remb_values->receive_bitrate = bitrate;</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_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_channel_unref(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "Set REMB %s override to a bitrate of %s on %s\n", a->argv[2], a->argv[3], a->argv[4]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</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_cli_entry remb_cli[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_CLI_DEFINE(handle_remb_set, "Set the REMB value which overwrites what is sent or received"),</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%);">+ ast_cli_register_multiple(remb_cli, ARRAY_LEN(remb_cli));</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_MODULE_LOAD_SUCCESS;</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%);">+ ast_cli_unregister_multiple(remb_cli, ARRAY_LEN(remb_cli));</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%);">+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "REMB Modifier Module",</span><br><span style="color: hsl(120, 100%, 40%);">+ .support_level = AST_MODULE_SUPPORT_EXTENDED,</span><br><span style="color: hsl(120, 100%, 40%);">+ .load = load_module,</span><br><span style="color: hsl(120, 100%, 40%);">+ .unload = unload_module,</span><br><span style="color: hsl(120, 100%, 40%);">+);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/10204">change 10204</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/10204"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Ib089427c46a4a36d645cecfe02406adb38c17bec </div>
<div style="display:none"> Gerrit-Change-Number: 10204 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 (1000185) </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Sean Bright <sean.bright@gmail.com> </div>