Asterisk - The Open Source Telephony Project GIT-master-a358458
Data Structures | Functions | Variables
res_remb_modifier.c File Reference

REMB Modifier Module. More...

#include "asterisk.h"
#include <math.h>
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/channel.h"
#include "asterisk/framehook.h"
#include "asterisk/rtp_engine.h"
Include dependency graph for res_remb_modifier.c:

Go to the source code of this file.

Data Structures

struct  remb_values
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static char * handle_remb_set (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int load_module (void)
 
static struct ast_frameremb_hook_event_cb (struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
 
static void remb_values_free (void *data)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "REMB Modifier Module" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry remb_cli []
 
static const struct ast_datastore_info remb_info
 

Detailed Description

REMB Modifier Module.

Author
Joshua Colp jcolp.nosp@m.@dig.nosp@m.ium.c.nosp@m.om

Definition in file res_remb_modifier.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 268 of file res_remb_modifier.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 268 of file res_remb_modifier.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 268 of file res_remb_modifier.c.

◆ handle_remb_set()

static char * handle_remb_set ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 155 of file res_remb_modifier.c.

156{
157 struct ast_channel *chan;
158 unsigned int bitrate;
159 struct ast_datastore *remb_store;
160 struct remb_values *remb_values;
161 struct ast_framehook_interface interface = {
163 .event_cb = remb_hook_event_cb,
164 };
165
166 switch(cmd) {
167 case CLI_INIT:
168 e->command = "remb set {send|receive}";
169 e->usage =
170 "Usage: remb set {send|receive} <channel> <bitrate in bits>\n"
171 " Set the REMB value which overwrites what we send or receive\n";
172 return NULL;
173 case CLI_GENERATE:
174 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
175 }
176
177 if (a->argc != 5) {
178 return CLI_SHOWUSAGE;
179 }
180
181 if (sscanf(a->argv[4], "%30d", &bitrate) != 1) {
182 ast_cli(a->fd, "%s is not a valid bitrate in bits\n", a->argv[4]);
183 return CLI_SUCCESS;
184 } else if (strcasecmp(a->argv[2], "send") && strcasecmp(a->argv[2], "receive")) {
185 ast_cli(a->fd, "%s is not a valid direction for REMB\n", a->argv[2]);
186 return CLI_SUCCESS;
187 }
188
189 chan = ast_channel_get_by_name(a->argv[3]);
190 if (!chan) {
191 ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
192 return CLI_SUCCESS;
193 }
194
195 ast_channel_lock(chan);
196
197 remb_store = ast_channel_datastore_find(chan, &remb_info, NULL);
198 if (!remb_store) {
199 int framehook_id;
200
201 framehook_id = ast_framehook_attach(chan, &interface);
202 if (framehook_id < 0) {
203 ast_cli(a->fd, "Could not attach framehook for modifying REMB\n");
204 ast_channel_unlock(chan);
205 ast_channel_unref(chan);
206 return CLI_SUCCESS;
207 }
208
209 remb_values = ast_calloc(1, sizeof(*remb_values));
210 if (!remb_values) {
211 ast_cli(a->fd, "Could not create a place to store provided REMB value\n");
212 ast_framehook_detach(chan, framehook_id);
213 ast_channel_unlock(chan);
214 ast_channel_unref(chan);
215 return CLI_SUCCESS;
216 }
217
218 remb_store = ast_datastore_alloc(&remb_info, NULL);
219 if (!remb_store) {
220 ast_cli(a->fd, "Could not create a place to store provided REMB value\n");
221 ast_framehook_detach(chan, framehook_id);
222 ast_channel_unlock(chan);
223 ast_channel_unref(chan);
225 return CLI_SUCCESS;
226 }
227
228 remb_store->data = remb_values;
229 ast_channel_datastore_add(chan, remb_store);
230 } else {
231 remb_values = remb_store->data;
232 }
233
234 if (!strcasecmp(a->argv[2], "send")) {
235 remb_values->send_bitrate = bitrate;
236 } else if (!strcasecmp(a->argv[2], "receive")) {
237 remb_values->receive_bitrate = bitrate;
238 }
239
240 ast_channel_unlock(chan);
241 ast_channel_unref(chan);
242
243 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]);
244
245 return CLI_SUCCESS;
246}
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
#define ast_channel_lock(chan)
Definition: channel.h:2922
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
#define ast_channel_unlock(chan)
Definition: channel.h:2923
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition: main/cli.c:1860
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_framehook_attach(struct ast_channel *chan, struct ast_framehook_interface *i)
Attach an framehook onto a channel for frame interception.
Definition: framehook.c:132
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition: framehook.c:177
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
static const struct ast_datastore_info remb_info
static struct ast_frame * remb_hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
#define NULL
Definition: resample.c:96
Main Channel structure associated with a channel.
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
float receive_bitrate
The amount of bitrate to use for REMB received from the channel.
float send_bitrate
The amount of bitrate to use for REMB sent to the channel.
static struct test_val a

References a, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_cli(), ast_complete_channels(), ast_datastore_alloc, ast_framehook_attach(), ast_framehook_detach(), AST_FRAMEHOOK_INTERFACE_VERSION, ast_free, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_datastore::data, NULL, remb_values::receive_bitrate, remb_hook_event_cb(), remb_info, remb_values::send_bitrate, ast_cli_entry::usage, and ast_framehook_interface::version.

◆ load_module()

static int load_module ( void  )
static

Definition at line 252 of file res_remb_modifier.c.

253{
256}
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
static struct ast_cli_entry remb_cli[]
#define ARRAY_LEN(a)
Definition: utils.h:666

References ARRAY_LEN, ast_cli_register_multiple, AST_MODULE_LOAD_SUCCESS, and remb_cli.

◆ remb_hook_event_cb()

static struct ast_frame * remb_hook_event_cb ( struct ast_channel chan,
struct ast_frame frame,
enum ast_framehook_event  event,
void *  data 
)
static

Definition at line 59 of file res_remb_modifier.c.

60{
61 struct ast_rtp_rtcp_feedback *feedback;
62 struct ast_datastore *remb_store;
64 int exp;
65 float bitrate = 0.0;
66
67 if (!frame) {
68 return NULL;
69 }
70
71 switch (event) {
74 break;
77 return frame;
78 }
79
80 /* We only care about REMB frames, all others will be unmodified */
81 if (frame->subclass.integer != AST_RTP_RTCP_PSFB) {
82 return frame;
83 }
84
85 feedback = frame->data.ptr;
86 if (feedback->fmt != AST_RTP_RTCP_FMT_REMB) {
87 return frame;
88 }
89
90 remb_store = ast_channel_datastore_find(chan, &remb_info, NULL);
91 if (!remb_store) {
92 return frame;
93 }
94 remb_values = remb_store->data;
95
96 /* If a bitrate override has been set apply it to the REMB Frame */
100 bitrate = remb_values->send_bitrate;
101 } else {
102 return frame;
103 }
104
105 /*
106 * The mantissa only has 18 bits available, so make sure it fits. Adjust the
107 * value and exponent for those values that don't.
108 *
109 * For example given the following:
110 *
111 * bitrate = 123456789.0
112 * frexp(bitrate, &exp);
113 *
114 * 'exp' should now equal 27 (number of bits needed to represent the value). Since
115 * the mantissa must fit into an 18-bit unsigned integer, and the given bitrate is
116 * too large to fit, we must subtract 18 from the exponent in order to get the
117 * number of times the bitrate will fit into that size integer.
118 *
119 * exp -= 18;
120 *
121 * 'exp' is now equal to 9. Now we can get the mantissa that fits into an 18-bit
122 * unsigned integer by dividing the bitrate by 2^exp:
123 *
124 * mantissa = 123456789.0 / 2^9
125 *
126 * This makes the final mantissa equal to 241126 (implicitly cast), which is less
127 * than 262143 (the max value that can be put into an unsigned 18-bit integer).
128 * So now we have the following:
129 *
130 * exp = 9;
131 * mantissa = 241126;
132 *
133 * If we multiply that back we should come up with something close to the original
134 * bit rate:
135 *
136 * 241126 * 2^9 = 123456512
137 *
138 * Precision is lost due to the nature of floating point values. Easier to why from
139 * the binary:
140 *
141 * 241126 * 2^9 = 241126 << 9 = 111010110111100110 << 9 = 111010110111100110000000000
142 *
143 * Precision on the "lower" end is lost due to zeros being shifted in. This loss is
144 * both expected and acceptable.
145 */
146 frexp(bitrate, &exp);
147 exp = exp > 18 ? exp - 18 : 0;
148
149 feedback->remb.br_mantissa = bitrate / (1 << exp);
150 feedback->remb.br_exp = exp;
151
152 return frame;
153}
@ AST_FRAMEHOOK_EVENT_ATTACHED
Definition: framehook.h:154
@ AST_FRAMEHOOK_EVENT_DETACHED
Definition: framehook.h:155
@ AST_FRAMEHOOK_EVENT_WRITE
Definition: framehook.h:153
@ AST_FRAMEHOOK_EVENT_READ
Definition: framehook.h:152
#define AST_RTP_RTCP_PSFB
Definition: rtp_engine.h:324
#define AST_RTP_RTCP_FMT_REMB
Definition: rtp_engine.h:334
struct ast_frame_subclass subclass
union ast_frame::@226 data
An object that represents data received in a feedback report.
Definition: rtp_engine.h:383
unsigned int fmt
Definition: rtp_engine.h:384
struct ast_rtp_rtcp_feedback_remb remb
Definition: rtp_engine.h:386
Definition: astman.c:222

References ast_channel_datastore_find(), AST_FRAMEHOOK_EVENT_ATTACHED, AST_FRAMEHOOK_EVENT_DETACHED, AST_FRAMEHOOK_EVENT_READ, AST_FRAMEHOOK_EVENT_WRITE, AST_RTP_RTCP_FMT_REMB, AST_RTP_RTCP_PSFB, ast_rtp_rtcp_feedback_remb::br_exp, ast_rtp_rtcp_feedback_remb::br_mantissa, ast_datastore::data, ast_frame::data, ast_rtp_rtcp_feedback::fmt, ast_frame_subclass::integer, NULL, ast_frame::ptr, remb_values::receive_bitrate, ast_rtp_rtcp_feedback::remb, remb_info, remb_values::send_bitrate, and ast_frame::subclass.

Referenced by handle_remb_set().

◆ remb_values_free()

static void remb_values_free ( void *  data)
static

Definition at line 49 of file res_remb_modifier.c.

50{
51 ast_free(data);
52}

References ast_free.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 258 of file res_remb_modifier.c.

259{
261 return 0;
262}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30

References ARRAY_LEN, ast_cli_unregister_multiple(), and remb_cli.

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "REMB Modifier Module" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, }
static

Definition at line 268 of file res_remb_modifier.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 268 of file res_remb_modifier.c.

◆ remb_cli

struct ast_cli_entry remb_cli[]
static
Initial value:
= {
{ .handler = handle_remb_set , .summary = "Set the REMB value which overwrites what is sent or received" ,},
}
static char * handle_remb_set(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 248 of file res_remb_modifier.c.

Referenced by load_module(), and unload_module().

◆ remb_info

const struct ast_datastore_info remb_info
static
Initial value:
= {
.type = "REMB Values",
.destroy = remb_values_free,
}
static void remb_values_free(void *data)

Definition at line 54 of file res_remb_modifier.c.

Referenced by handle_remb_set(), and remb_hook_event_cb().