Asterisk - The Open Source Telephony Project  18.5.0
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[email protected]@dig[email protected]ium.c[email protected]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.

References ast_cli_args::argc, ast_cli_args::argv, 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, ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, NULL, ast_cli_args::pos, remb_values::receive_bitrate, remb_hook_event_cb(), remb_values::send_bitrate, ast_cli_entry::usage, ast_framehook_interface::version, and ast_cli_args::word.

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);
224  ast_free(remb_values);
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_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
float send_bitrate
The amount of bitrate to use for REMB sent to the channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
const int argc
Definition: cli.h:160
int ast_framehook_detach(struct ast_channel *chan, int framehook_id)
Detach an framehook from a channel.
Definition: framehook.c:177
Definition: cli.h:152
Structure for a data store object.
Definition: datastore.h:68
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:2404
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
float receive_bitrate
The amount of bitrate to use for REMB received from the channel.
const char * line
Definition: cli.h:162
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
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define AST_FRAMEHOOK_INTERFACE_VERSION
Definition: framehook.h:227
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static const struct ast_datastore_info remb_info
const char * word
Definition: cli.h:163
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
void * data
Definition: datastore.h:70
const int pos
Definition: cli.h:164
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:1830
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
static struct ast_frame * remb_hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)

◆ load_module()

static int load_module ( void  )
static

Definition at line 252 of file res_remb_modifier.c.

References ARRAY_LEN, ast_cli_register_multiple, and AST_MODULE_LOAD_SUCCESS.

Referenced by unload_module().

253 {
256 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static struct ast_cli_entry 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.

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_values::send_bitrate, and ast_frame::subclass.

Referenced by handle_remb_set().

60 {
61  struct ast_rtp_rtcp_feedback *feedback;
62  struct ast_datastore *remb_store;
63  struct remb_values *remb_values;
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 */
97  if (event == AST_FRAMEHOOK_EVENT_READ && remb_values->receive_bitrate) {
98  bitrate = remb_values->receive_bitrate;
99  } else if (event == AST_FRAMEHOOK_EVENT_WRITE && remb_values->send_bitrate) {
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 }
float send_bitrate
The amount of bitrate to use for REMB sent to the channel.
An object that represents data received in a feedback report.
Definition: rtp_engine.h:358
Definition: astman.c:222
Structure for a data store object.
Definition: datastore.h:68
unsigned int fmt
Definition: rtp_engine.h:359
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:2404
struct ast_rtp_rtcp_feedback_remb remb
Definition: rtp_engine.h:361
#define NULL
Definition: resample.c:96
float receive_bitrate
The amount of bitrate to use for REMB received from the channel.
struct ast_frame_subclass subclass
static const struct ast_datastore_info remb_info
void * data
Definition: datastore.h:70
#define AST_RTP_RTCP_PSFB
Definition: rtp_engine.h:299
union ast_frame::@263 data
#define AST_RTP_RTCP_FMT_REMB
Definition: rtp_engine.h:309

◆ remb_values_free()

static void remb_values_free ( void *  data)
static

Definition at line 49 of file res_remb_modifier.c.

References ast_free.

50 {
51  ast_free(data);
52 }
#define ast_free(a)
Definition: astmm.h:182

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 258 of file res_remb_modifier.c.

References ARRAY_LEN, ast_cli_unregister_multiple(), AST_MODFLAG_DEFAULT, AST_MODULE_INFO(), AST_MODULE_SUPPORT_EXTENDED, ASTERISK_GPL_KEY, and load_module().

259 {
261  return 0;
262 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
static struct ast_cli_entry 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.

◆ 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.