Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Macros | Functions | Variables
func_speex.c File Reference

Noise reduction and automatic gain control (AGC) More...

#include "asterisk.h"
#include <speex/speex_preprocess.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/audiohook.h"
Include dependency graph for func_speex.c:

Go to the source code of this file.

Data Structures

struct  speex_direction_info
 
struct  speex_info
 

Macros

#define DEFAULT_AGC_LEVEL   8000.0
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void destroy_callback (void *data)
 
static int load_module (void)
 
static int speex_callback (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
 
static int speex_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int speex_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Noise reduction and Automatic Gain Control (AGC)" , .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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static struct ast_custom_function agc_function
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_custom_function denoise_function
 
static const struct ast_datastore_info speex_datastore
 

Detailed Description

Noise reduction and automatic gain control (AGC)

Author
Brian Degenhardt bmd@d.nosp@m.igiu.nosp@m.m.com
Brett Bryant bbrya.nosp@m.nt@d.nosp@m.igium.nosp@m..com

The Speex 1.2 library - http://www.speex.org

Note
Requires the 1.2 version of the Speex library (which might not be what you find in Linux packages)

Definition in file func_speex.c.

Macro Definition Documentation

◆ DEFAULT_AGC_LEVEL

#define DEFAULT_AGC_LEVEL   8000.0

Definition at line 49 of file func_speex.c.

Referenced by speex_write().

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 382 of file func_speex.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 382 of file func_speex.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 382 of file func_speex.c.

◆ destroy_callback()

static void destroy_callback ( void *  data)
static

Definition at line 111 of file func_speex.c.

References ast_audiohook_destroy(), ast_free, speex_info::audiohook, speex_info::rx, speex_direction_info::state, and speex_info::tx.

112 {
113  struct speex_info *si = data;
114 
116 
117  if (si->rx && si->rx->state) {
118  speex_preprocess_state_destroy(si->rx->state);
119  }
120 
121  if (si->tx && si->tx->state) {
122  speex_preprocess_state_destroy(si->tx->state);
123  }
124 
125  if (si->rx) {
126  ast_free(si->rx);
127  }
128 
129  if (si->tx) {
130  ast_free(si->tx);
131  }
132 
133  ast_free(data);
134 };
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:133
struct ast_audiohook audiohook
Definition: func_speex.c:106
struct speex_direction_info * tx
Definition: func_speex.c:108
#define ast_free(a)
Definition: astmm.h:182
struct speex_direction_info * rx
Definition: func_speex.c:108
SpeexPreprocessState * state
Definition: func_speex.c:98

◆ load_module()

static int load_module ( void  )
static

Definition at line 368 of file func_speex.c.

References ast_custom_function_register, ast_custom_function_unregister(), AST_MODULE_LOAD_DECLINE, and AST_MODULE_LOAD_SUCCESS.

369 {
372  }
373 
377  }
378 
380 }
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static struct ast_custom_function denoise_function
Definition: func_speex.c:354
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static struct ast_custom_function agc_function
Definition: func_speex.c:347
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508

◆ speex_callback()

static int speex_callback ( struct ast_audiohook audiohook,
struct ast_channel chan,
struct ast_frame frame,
enum ast_audiohook_direction  direction 
)
static

Definition at line 141 of file func_speex.c.

References speex_direction_info::agc, speex_direction_info::agclevel, AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), ast_format_get_sample_rate(), AST_FRAME_VOICE, ast_free, AST_MALLOCD_SRC, ast_strdup, ast_datastore::data, ast_frame::data, speex_direction_info::denoise, ast_frame_subclass::format, ast_frame::frametype, if(), speex_info::lastrate, ast_frame::mallocd, NULL, ast_frame::ptr, speex_info::rx, speex_direction_info::samples, ast_frame::samples, ast_frame::src, speex_direction_info::state, ast_audiohook::status, ast_frame::subclass, and speex_info::tx.

Referenced by speex_write().

142 {
143  struct ast_datastore *datastore = NULL;
144  struct speex_direction_info *sdi = NULL;
145  struct speex_info *si = NULL;
146  char source[80];
147 
148  /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
149  if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || frame->frametype != AST_FRAME_VOICE) {
150  return -1;
151  }
152 
153  /* We are called with chan already locked */
154  if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
155  return -1;
156  }
157 
158  si = datastore->data;
159 
160  sdi = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? si->rx : si->tx;
161 
162  if (!sdi) {
163  return -1;
164  }
165 
166  if ((sdi->samples != frame->samples) || (ast_format_get_sample_rate(frame->subclass.format) != si->lastrate)) {
168  if (sdi->state) {
169  speex_preprocess_state_destroy(sdi->state);
170  }
171 
172  if (!(sdi->state = speex_preprocess_state_init((sdi->samples = frame->samples), si->lastrate))) {
173  return -1;
174  }
175 
176  speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC, &sdi->agc);
177 
178  if (sdi->agc) {
179  speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &sdi->agclevel);
180  }
181 
182  speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_DENOISE, &sdi->denoise);
183  }
184 
185  speex_preprocess(sdi->state, frame->data.ptr, NULL);
186  snprintf(source, sizeof(source), "%s/speex", frame->src);
187  if (frame->mallocd & AST_MALLOCD_SRC) {
188  ast_free((char *) frame->src);
189  }
190  frame->src = ast_strdup(source);
191  frame->mallocd |= AST_MALLOCD_SRC;
192 
193  return 0;
194 }
int lastrate
Definition: func_speex.c:107
if(!yyg->yy_init)
Definition: ast_expr2f.c:868
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
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
static const struct ast_datastore_info speex_datastore
Definition: func_speex.c:136
struct ast_frame_subclass subclass
const char * src
struct speex_direction_info * tx
Definition: func_speex.c:108
#define ast_free(a)
Definition: astmm.h:182
void * data
Definition: datastore.h:70
struct speex_direction_info * rx
Definition: func_speex.c:108
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition: format.c:379
enum ast_audiohook_status status
Definition: audiohook.h:107
union ast_frame::@263 data
enum ast_frame_type frametype
#define AST_MALLOCD_SRC
struct ast_format * format
direction
SpeexPreprocessState * state
Definition: func_speex.c:98

◆ speex_read()

static int speex_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 310 of file func_speex.c.

References speex_direction_info::agclevel, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_log, ast_datastore::data, speex_direction_info::denoise, LOG_ERROR, NULL, speex_info::rx, and speex_info::tx.

311 {
312  struct ast_datastore *datastore = NULL;
313  struct speex_info *si = NULL;
314  struct speex_direction_info *sdi = NULL;
315 
316  if (!chan) {
317  ast_log(LOG_ERROR, "%s cannot be used without a channel!\n", cmd);
318  return -1;
319  }
320 
321  ast_channel_lock(chan);
322  if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
323  ast_channel_unlock(chan);
324  return -1;
325  }
326  ast_channel_unlock(chan);
327 
328  si = datastore->data;
329 
330  if (!strcasecmp(data, "tx"))
331  sdi = si->tx;
332  else if (!strcasecmp(data, "rx"))
333  sdi = si->rx;
334  else {
335  ast_log(LOG_ERROR, "%s(%s) must either \"tx\" or \"rx\"\n", cmd, data);
336  return -1;
337  }
338 
339  if (!strcasecmp(cmd, "agc"))
340  snprintf(buf, len, "%.01f", sdi ? sdi->agclevel : 0.0);
341  else
342  snprintf(buf, len, "%d", sdi ? sdi->denoise : 0);
343 
344  return 0;
345 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
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
static const struct ast_datastore_info speex_datastore
Definition: func_speex.c:136
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
struct speex_direction_info * tx
Definition: func_speex.c:108
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void * data
Definition: datastore.h:70
struct speex_direction_info * rx
Definition: func_speex.c:108

◆ speex_write()

static int speex_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
)
static

Definition at line 196 of file func_speex.c.

References ast_audiohook_attach(), ast_audiohook_detach(), ast_audiohook_init(), AST_AUDIOHOOK_MANIPULATE_ALL_RATES, ast_audiohook_remove(), AST_AUDIOHOOK_TYPE_MANIPULATE, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), ast_free, ast_log, ast_true(), speex_info::audiohook, ast_datastore::data, DEFAULT_AGC_LEVEL, speex_info::lastrate, LOG_ERROR, LOG_WARNING, ast_audiohook::manipulate_callback, NULL, speex_info::rx, speex_direction_info::samples, speex_callback(), and speex_info::tx.

197 {
198  struct ast_datastore *datastore = NULL;
199  struct speex_info *si = NULL;
200  struct speex_direction_info **sdi = NULL;
201  int is_new = 0;
202 
203  if (!chan) {
204  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
205  return -1;
206  }
207 
208  if (strcasecmp(data, "rx") && strcasecmp(data, "tx")) {
209  ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
210  return -1;
211  }
212 
213  ast_channel_lock(chan);
214  if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
215  ast_channel_unlock(chan);
216 
217  if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) {
218  return 0;
219  }
220 
221  if (!(si = ast_calloc(1, sizeof(*si)))) {
222  ast_datastore_free(datastore);
223  return 0;
224  }
225 
228  si->lastrate = 8000;
229  is_new = 1;
230  } else {
231  ast_channel_unlock(chan);
232  si = datastore->data;
233  }
234 
235  if (!strcasecmp(data, "rx")) {
236  sdi = &si->rx;
237  } else {
238  sdi = &si->tx;
239  }
240 
241  if (!*sdi) {
242  if (!(*sdi = ast_calloc(1, sizeof(**sdi)))) {
243  return 0;
244  }
245  /* Right now, the audiohooks API will _only_ provide us 8 kHz slinear
246  * audio. When it supports 16 kHz (or any other sample rates, we will
247  * have to take that into account here. */
248  (*sdi)->samples = -1;
249  }
250 
251  if (!strcasecmp(cmd, "agc")) {
252  if (!sscanf(value, "%30f", &(*sdi)->agclevel))
253  (*sdi)->agclevel = ast_true(value) ? DEFAULT_AGC_LEVEL : 0.0;
254 
255  if ((*sdi)->agclevel > 32768.0) {
256  ast_log(LOG_WARNING, "AGC(%s)=%.01f is greater than 32768... setting to 32768 instead\n",
257  ((*sdi == si->rx) ? "rx" : "tx"), (*sdi)->agclevel);
258  (*sdi)->agclevel = 32768.0;
259  }
260 
261  (*sdi)->agc = !!((*sdi)->agclevel);
262 
263  if ((*sdi)->state) {
264  speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC, &(*sdi)->agc);
265  if ((*sdi)->agc) {
266  speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &(*sdi)->agclevel);
267  }
268  }
269  } else if (!strcasecmp(cmd, "denoise")) {
270  (*sdi)->denoise = (ast_true(value) != 0);
271 
272  if ((*sdi)->state) {
273  speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_DENOISE, &(*sdi)->denoise);
274  }
275  }
276 
277  if (!(*sdi)->agc && !(*sdi)->denoise) {
278  if ((*sdi)->state)
279  speex_preprocess_state_destroy((*sdi)->state);
280 
281  ast_free(*sdi);
282  *sdi = NULL;
283  }
284 
285  if (!si->rx && !si->tx) {
286  if (is_new) {
287  is_new = 0;
288  } else {
289  ast_channel_lock(chan);
290  ast_channel_datastore_remove(chan, datastore);
291  ast_channel_unlock(chan);
292  ast_audiohook_remove(chan, &si->audiohook);
294  }
295 
296  ast_datastore_free(datastore);
297  }
298 
299  if (is_new) {
300  datastore->data = si;
301  ast_channel_lock(chan);
302  ast_channel_datastore_add(chan, datastore);
303  ast_channel_unlock(chan);
304  ast_audiohook_attach(chan, &si->audiohook);
305  }
306 
307  return 0;
308 }
int lastrate
Definition: func_speex.c:107
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define LOG_WARNING
Definition: logger.h:274
int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
Remove an audiohook from a specified channel.
Definition: audiohook.c:764
static int speex_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
Definition: func_speex.c:141
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:501
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
static const struct ast_datastore_info speex_datastore
Definition: func_speex.c:136
int value
Definition: syslog.c:37
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
ast_audiohook_manipulate_callback manipulate_callback
Definition: audiohook.h:117
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition: audiohook.c:108
struct ast_audiohook audiohook
Definition: func_speex.c:106
#define ast_log
Definition: astobj2.c:42
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:579
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
struct speex_direction_info * tx
Definition: func_speex.c:108
#define DEFAULT_AGC_LEVEL
Definition: func_speex.c:49
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
void * data
Definition: datastore.h:70
struct speex_direction_info * rx
Definition: func_speex.c:108
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 361 of file func_speex.c.

References ast_custom_function_unregister().

362 {
365  return 0;
366 }
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static struct ast_custom_function denoise_function
Definition: func_speex.c:354
static struct ast_custom_function agc_function
Definition: func_speex.c:347

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Noise reduction and Automatic Gain Control (AGC)" , .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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 382 of file func_speex.c.

◆ agc_function

struct ast_custom_function agc_function
static

Definition at line 347 of file func_speex.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 382 of file func_speex.c.

◆ denoise_function

struct ast_custom_function denoise_function
static

Definition at line 354 of file func_speex.c.

◆ speex_datastore

const struct ast_datastore_info speex_datastore
static
Initial value:
= {
.type = "speex",
.destroy = destroy_callback
}
static void destroy_callback(void *data)
Definition: func_speex.c:111

Definition at line 136 of file func_speex.c.