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"
Go to the source code of this file.
Data Structures | |
struct | speex_direction_info |
struct | speex_info |
Defines | |
#define | DEFAULT_AGC_LEVEL 8000.0 |
Functions | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Noise reduction and Automatic Gain Control (AGC)") | |
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_custom_function | agc_function |
static struct ast_custom_function | denoise_function |
static struct ast_datastore_info | speex_datastore |
Noise reduction and automatic gain control (AGC).
Definition in file func_speex.c.
#define DEFAULT_AGC_LEVEL 8000.0 |
Definition at line 51 of file func_speex.c.
Referenced by speex_write().
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Noise reduction and Automatic Gain Control (AGC)" | ||||
) |
static void destroy_callback | ( | void * | data | ) | [static] |
Definition at line 112 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.
00113 { 00114 struct speex_info *si = data; 00115 00116 ast_audiohook_destroy(&si->audiohook); 00117 00118 if (si->rx && si->rx->state) { 00119 speex_preprocess_state_destroy(si->rx->state); 00120 } 00121 00122 if (si->tx && si->tx->state) { 00123 speex_preprocess_state_destroy(si->tx->state); 00124 } 00125 00126 if (si->rx) { 00127 ast_free(si->rx); 00128 } 00129 00130 if (si->tx) { 00131 ast_free(si->tx); 00132 } 00133 00134 ast_free(data); 00135 };
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.
00369 { 00370 if (ast_custom_function_register(&agc_function)) { 00371 return AST_MODULE_LOAD_DECLINE; 00372 } 00373 00374 if (ast_custom_function_register(&denoise_function)) { 00375 ast_custom_function_unregister(&agc_function); 00376 return AST_MODULE_LOAD_DECLINE; 00377 } 00378 00379 return AST_MODULE_LOAD_SUCCESS; 00380 }
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 142 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_FRAME_VOICE, ast_free, AST_MALLOCD_SRC, ast_strdup, ast_frame::data, ast_datastore::data, speex_direction_info::denoise, ast_frame::frametype, ast_frame::mallocd, ast_frame::ptr, speex_info::rx, ast_frame::samples, speex_direction_info::samples, ast_frame::src, speex_direction_info::state, ast_audiohook::status, and speex_info::tx.
Referenced by speex_write().
00143 { 00144 struct ast_datastore *datastore = NULL; 00145 struct speex_direction_info *sdi = NULL; 00146 struct speex_info *si = NULL; 00147 char source[80]; 00148 00149 /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */ 00150 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || frame->frametype != AST_FRAME_VOICE) { 00151 return -1; 00152 } 00153 00154 /* We are called with chan already locked */ 00155 if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) { 00156 return -1; 00157 } 00158 00159 si = datastore->data; 00160 00161 sdi = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? si->rx : si->tx; 00162 00163 if (!sdi) { 00164 return -1; 00165 } 00166 00167 if (sdi->samples != frame->samples) { 00168 if (sdi->state) { 00169 speex_preprocess_state_destroy(sdi->state); 00170 } 00171 00172 if (!(sdi->state = speex_preprocess_state_init((sdi->samples = frame->samples), 8000))) { 00173 return -1; 00174 } 00175 00176 speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC, &sdi->agc); 00177 00178 if (sdi->agc) { 00179 speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &sdi->agclevel); 00180 } 00181 00182 speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_DENOISE, &sdi->denoise); 00183 } 00184 00185 speex_preprocess(sdi->state, frame->data.ptr, NULL); 00186 snprintf(source, sizeof(source), "%s/speex", frame->src); 00187 if (frame->mallocd & AST_MALLOCD_SRC) { 00188 ast_free((char *) frame->src); 00189 } 00190 frame->src = ast_strdup(source); 00191 frame->mallocd |= AST_MALLOCD_SRC; 00192 00193 return 0; 00194 }
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, speex_info::rx, and speex_info::tx.
00311 { 00312 struct ast_datastore *datastore = NULL; 00313 struct speex_info *si = NULL; 00314 struct speex_direction_info *sdi = NULL; 00315 00316 if (!chan) { 00317 ast_log(LOG_ERROR, "%s cannot be used without a channel!\n", cmd); 00318 return -1; 00319 } 00320 00321 ast_channel_lock(chan); 00322 if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) { 00323 ast_channel_unlock(chan); 00324 return -1; 00325 } 00326 ast_channel_unlock(chan); 00327 00328 si = datastore->data; 00329 00330 if (!strcasecmp(data, "tx")) 00331 sdi = si->tx; 00332 else if (!strcasecmp(data, "rx")) 00333 sdi = si->rx; 00334 else { 00335 ast_log(LOG_ERROR, "%s(%s) must either \"tx\" or \"rx\"\n", cmd, data); 00336 return -1; 00337 } 00338 00339 if (!strcasecmp(cmd, "agc")) 00340 snprintf(buf, len, "%.01f", sdi ? sdi->agclevel : 0.0); 00341 else 00342 snprintf(buf, len, "%d", sdi ? sdi->denoise : 0); 00343 00344 return 0; 00345 }
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_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, LOG_ERROR, LOG_WARNING, ast_audiohook::manipulate_callback, speex_info::rx, speex_direction_info::samples, speex_callback(), and speex_info::tx.
00197 { 00198 struct ast_datastore *datastore = NULL; 00199 struct speex_info *si = NULL; 00200 struct speex_direction_info **sdi = NULL; 00201 int is_new = 0; 00202 00203 if (!chan) { 00204 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd); 00205 return -1; 00206 } 00207 00208 if (strcasecmp(data, "rx") && strcasecmp(data, "tx")) { 00209 ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd); 00210 return -1; 00211 } 00212 00213 ast_channel_lock(chan); 00214 if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) { 00215 ast_channel_unlock(chan); 00216 00217 if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) { 00218 return 0; 00219 } 00220 00221 if (!(si = ast_calloc(1, sizeof(*si)))) { 00222 ast_datastore_free(datastore); 00223 return 0; 00224 } 00225 00226 ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex"); 00227 si->audiohook.manipulate_callback = speex_callback; 00228 00229 is_new = 1; 00230 } else { 00231 ast_channel_unlock(chan); 00232 si = datastore->data; 00233 } 00234 00235 if (!strcasecmp(data, "rx")) { 00236 sdi = &si->rx; 00237 } else { 00238 sdi = &si->tx; 00239 } 00240 00241 if (!*sdi) { 00242 if (!(*sdi = ast_calloc(1, sizeof(**sdi)))) { 00243 return 0; 00244 } 00245 /* Right now, the audiohooks API will _only_ provide us 8 kHz slinear 00246 * audio. When it supports 16 kHz (or any other sample rates, we will 00247 * have to take that into account here. */ 00248 (*sdi)->samples = -1; 00249 } 00250 00251 if (!strcasecmp(cmd, "agc")) { 00252 if (!sscanf(value, "%30f", &(*sdi)->agclevel)) 00253 (*sdi)->agclevel = ast_true(value) ? DEFAULT_AGC_LEVEL : 0.0; 00254 00255 if ((*sdi)->agclevel > 32768.0) { 00256 ast_log(LOG_WARNING, "AGC(%s)=%.01f is greater than 32768... setting to 32768 instead\n", 00257 ((*sdi == si->rx) ? "rx" : "tx"), (*sdi)->agclevel); 00258 (*sdi)->agclevel = 32768.0; 00259 } 00260 00261 (*sdi)->agc = !!((*sdi)->agclevel); 00262 00263 if ((*sdi)->state) { 00264 speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC, &(*sdi)->agc); 00265 if ((*sdi)->agc) { 00266 speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &(*sdi)->agclevel); 00267 } 00268 } 00269 } else if (!strcasecmp(cmd, "denoise")) { 00270 (*sdi)->denoise = (ast_true(value) != 0); 00271 00272 if ((*sdi)->state) { 00273 speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_DENOISE, &(*sdi)->denoise); 00274 } 00275 } 00276 00277 if (!(*sdi)->agc && !(*sdi)->denoise) { 00278 if ((*sdi)->state) 00279 speex_preprocess_state_destroy((*sdi)->state); 00280 00281 ast_free(*sdi); 00282 *sdi = NULL; 00283 } 00284 00285 if (!si->rx && !si->tx) { 00286 if (is_new) { 00287 is_new = 0; 00288 } else { 00289 ast_channel_lock(chan); 00290 ast_channel_datastore_remove(chan, datastore); 00291 ast_channel_unlock(chan); 00292 ast_audiohook_remove(chan, &si->audiohook); 00293 ast_audiohook_detach(&si->audiohook); 00294 } 00295 00296 ast_datastore_free(datastore); 00297 } 00298 00299 if (is_new) { 00300 datastore->data = si; 00301 ast_channel_lock(chan); 00302 ast_channel_datastore_add(chan, datastore); 00303 ast_channel_unlock(chan); 00304 ast_audiohook_attach(chan, &si->audiohook); 00305 } 00306 00307 return 0; 00308 }
static int unload_module | ( | void | ) | [static] |
Definition at line 361 of file func_speex.c.
References ast_custom_function_unregister().
00362 { 00363 ast_custom_function_unregister(&agc_function); 00364 ast_custom_function_unregister(&denoise_function); 00365 return 0; 00366 }
struct ast_custom_function agc_function [static] |
Definition at line 347 of file func_speex.c.
struct ast_custom_function denoise_function [static] |
Definition at line 354 of file func_speex.c.
struct ast_datastore_info speex_datastore [static] |
{ .type = "speex", .destroy = destroy_callback }
Definition at line 137 of file func_speex.c.