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 363 of file func_speex.c.
References ast_custom_function_register, ast_custom_function_unregister(), AST_MODULE_LOAD_DECLINE, and AST_MODULE_LOAD_SUCCESS.
00364 { 00365 if (ast_custom_function_register(&agc_function)) { 00366 return AST_MODULE_LOAD_DECLINE; 00367 } 00368 00369 if (ast_custom_function_register(&denoise_function)) { 00370 ast_custom_function_unregister(&agc_function); 00371 return AST_MODULE_LOAD_DECLINE; 00372 } 00373 00374 return AST_MODULE_LOAD_SUCCESS; 00375 }
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 305 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.
00306 { 00307 struct ast_datastore *datastore = NULL; 00308 struct speex_info *si = NULL; 00309 struct speex_direction_info *sdi = NULL; 00310 00311 if (!chan) { 00312 ast_log(LOG_ERROR, "%s cannot be used without a channel!\n", cmd); 00313 return -1; 00314 } 00315 00316 ast_channel_lock(chan); 00317 if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) { 00318 ast_channel_unlock(chan); 00319 return -1; 00320 } 00321 ast_channel_unlock(chan); 00322 00323 si = datastore->data; 00324 00325 if (!strcasecmp(data, "tx")) 00326 sdi = si->tx; 00327 else if (!strcasecmp(data, "rx")) 00328 sdi = si->rx; 00329 else { 00330 ast_log(LOG_ERROR, "%s(%s) must either \"tx\" or \"rx\"\n", cmd, data); 00331 return -1; 00332 } 00333 00334 if (!strcasecmp(cmd, "agc")) 00335 snprintf(buf, len, "%.01f", sdi ? sdi->agclevel : 0.0); 00336 else 00337 snprintf(buf, len, "%d", sdi ? sdi->denoise : 0); 00338 00339 return 0; 00340 }
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 (strcasecmp(data, "rx") && strcasecmp(data, "tx")) { 00204 ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd); 00205 return -1; 00206 } 00207 00208 ast_channel_lock(chan); 00209 if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) { 00210 ast_channel_unlock(chan); 00211 00212 if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) { 00213 return 0; 00214 } 00215 00216 if (!(si = ast_calloc(1, sizeof(*si)))) { 00217 ast_datastore_free(datastore); 00218 return 0; 00219 } 00220 00221 ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex"); 00222 si->audiohook.manipulate_callback = speex_callback; 00223 00224 is_new = 1; 00225 } else { 00226 ast_channel_unlock(chan); 00227 si = datastore->data; 00228 } 00229 00230 if (!strcasecmp(data, "rx")) { 00231 sdi = &si->rx; 00232 } else { 00233 sdi = &si->tx; 00234 } 00235 00236 if (!*sdi) { 00237 if (!(*sdi = ast_calloc(1, sizeof(**sdi)))) { 00238 return 0; 00239 } 00240 /* Right now, the audiohooks API will _only_ provide us 8 kHz slinear 00241 * audio. When it supports 16 kHz (or any other sample rates, we will 00242 * have to take that into account here. */ 00243 (*sdi)->samples = -1; 00244 } 00245 00246 if (!strcasecmp(cmd, "agc")) { 00247 if (!sscanf(value, "%30f", &(*sdi)->agclevel)) 00248 (*sdi)->agclevel = ast_true(value) ? DEFAULT_AGC_LEVEL : 0.0; 00249 00250 if ((*sdi)->agclevel > 32768.0) { 00251 ast_log(LOG_WARNING, "AGC(%s)=%.01f is greater than 32768... setting to 32768 instead\n", 00252 ((*sdi == si->rx) ? "rx" : "tx"), (*sdi)->agclevel); 00253 (*sdi)->agclevel = 32768.0; 00254 } 00255 00256 (*sdi)->agc = !!((*sdi)->agclevel); 00257 00258 if ((*sdi)->state) { 00259 speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC, &(*sdi)->agc); 00260 if ((*sdi)->agc) { 00261 speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &(*sdi)->agclevel); 00262 } 00263 } 00264 } else if (!strcasecmp(cmd, "denoise")) { 00265 (*sdi)->denoise = (ast_true(value) != 0); 00266 00267 if ((*sdi)->state) { 00268 speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_DENOISE, &(*sdi)->denoise); 00269 } 00270 } 00271 00272 if (!(*sdi)->agc && !(*sdi)->denoise) { 00273 if ((*sdi)->state) 00274 speex_preprocess_state_destroy((*sdi)->state); 00275 00276 ast_free(*sdi); 00277 *sdi = NULL; 00278 } 00279 00280 if (!si->rx && !si->tx) { 00281 if (is_new) { 00282 is_new = 0; 00283 } else { 00284 ast_channel_lock(chan); 00285 ast_channel_datastore_remove(chan, datastore); 00286 ast_channel_unlock(chan); 00287 ast_audiohook_remove(chan, &si->audiohook); 00288 ast_audiohook_detach(&si->audiohook); 00289 } 00290 00291 ast_datastore_free(datastore); 00292 } 00293 00294 if (is_new) { 00295 datastore->data = si; 00296 ast_channel_lock(chan); 00297 ast_channel_datastore_add(chan, datastore); 00298 ast_channel_unlock(chan); 00299 ast_audiohook_attach(chan, &si->audiohook); 00300 } 00301 00302 return 0; 00303 }
static int unload_module | ( | void | ) | [static] |
Definition at line 356 of file func_speex.c.
References ast_custom_function_unregister().
00357 { 00358 ast_custom_function_unregister(&agc_function); 00359 ast_custom_function_unregister(&denoise_function); 00360 return 0; 00361 }
struct ast_custom_function agc_function [static] |
Definition at line 342 of file func_speex.c.
struct ast_custom_function denoise_function [static] |
Definition at line 349 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.