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 | |
| static void | __reg_module (void) |
| static void | __unreg_module (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_DEFAULT , .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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, } |
| static struct ast_custom_function | agc_function |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| 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 49 of file func_speex.c.
Referenced by speex_write().
| static void __reg_module | ( | void | ) | [static] |
Definition at line 375 of file func_speex.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 375 of file func_speex.c.
| static void destroy_callback | ( | void * | data | ) | [static] |
Definition at line 110 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.
00111 { 00112 struct speex_info *si = data; 00113 00114 ast_audiohook_destroy(&si->audiohook); 00115 00116 if (si->rx && si->rx->state) { 00117 speex_preprocess_state_destroy(si->rx->state); 00118 } 00119 00120 if (si->tx && si->tx->state) { 00121 speex_preprocess_state_destroy(si->tx->state); 00122 } 00123 00124 if (si->rx) { 00125 ast_free(si->rx); 00126 } 00127 00128 if (si->tx) { 00129 ast_free(si->tx); 00130 } 00131 00132 ast_free(data); 00133 };
| static int load_module | ( | void | ) | [static] |
Definition at line 361 of file func_speex.c.
References ast_custom_function_register, ast_custom_function_unregister(), AST_MODULE_LOAD_DECLINE, and AST_MODULE_LOAD_SUCCESS.
00362 { 00363 if (ast_custom_function_register(&agc_function)) { 00364 return AST_MODULE_LOAD_DECLINE; 00365 } 00366 00367 if (ast_custom_function_register(&denoise_function)) { 00368 ast_custom_function_unregister(&agc_function); 00369 return AST_MODULE_LOAD_DECLINE; 00370 } 00371 00372 return AST_MODULE_LOAD_SUCCESS; 00373 }
| 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 140 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().
00141 { 00142 struct ast_datastore *datastore = NULL; 00143 struct speex_direction_info *sdi = NULL; 00144 struct speex_info *si = NULL; 00145 char source[80]; 00146 00147 /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */ 00148 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || frame->frametype != AST_FRAME_VOICE) { 00149 return -1; 00150 } 00151 00152 /* We are called with chan already locked */ 00153 if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) { 00154 return -1; 00155 } 00156 00157 si = datastore->data; 00158 00159 sdi = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? si->rx : si->tx; 00160 00161 if (!sdi) { 00162 return -1; 00163 } 00164 00165 if (sdi->samples != frame->samples) { 00166 if (sdi->state) { 00167 speex_preprocess_state_destroy(sdi->state); 00168 } 00169 00170 if (!(sdi->state = speex_preprocess_state_init((sdi->samples = frame->samples), 8000))) { 00171 return -1; 00172 } 00173 00174 speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC, &sdi->agc); 00175 00176 if (sdi->agc) { 00177 speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &sdi->agclevel); 00178 } 00179 00180 speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_DENOISE, &sdi->denoise); 00181 } 00182 00183 speex_preprocess(sdi->state, frame->data.ptr, NULL); 00184 snprintf(source, sizeof(source), "%s/speex", frame->src); 00185 if (frame->mallocd & AST_MALLOCD_SRC) { 00186 ast_free((char *) frame->src); 00187 } 00188 frame->src = ast_strdup(source); 00189 frame->mallocd |= AST_MALLOCD_SRC; 00190 00191 return 0; 00192 }
| 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 194 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_callback(), and speex_info::tx.
00195 { 00196 struct ast_datastore *datastore = NULL; 00197 struct speex_info *si = NULL; 00198 struct speex_direction_info **sdi = NULL; 00199 int is_new = 0; 00200 00201 ast_channel_lock(chan); 00202 if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) { 00203 ast_channel_unlock(chan); 00204 00205 if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) { 00206 return 0; 00207 } 00208 00209 if (!(si = ast_calloc(1, sizeof(*si)))) { 00210 ast_datastore_free(datastore); 00211 return 0; 00212 } 00213 00214 ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex"); 00215 si->audiohook.manipulate_callback = speex_callback; 00216 00217 is_new = 1; 00218 } else { 00219 ast_channel_unlock(chan); 00220 si = datastore->data; 00221 } 00222 00223 if (!strcasecmp(data, "rx")) { 00224 sdi = &si->rx; 00225 } else if (!strcasecmp(data, "tx")) { 00226 sdi = &si->tx; 00227 } else { 00228 ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd); 00229 00230 if (is_new) { 00231 ast_datastore_free(datastore); 00232 return -1; 00233 } 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 354 of file func_speex.c.
References ast_custom_function_unregister().
00355 { 00356 ast_custom_function_unregister(&agc_function); 00357 ast_custom_function_unregister(&denoise_function); 00358 return 0; 00359 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 375 of file func_speex.c.
struct ast_custom_function agc_function [static] |
{
.name = "AGC",
.write = speex_write,
.read = speex_read
}
Definition at line 342 of file func_speex.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 375 of file func_speex.c.
struct ast_custom_function denoise_function [static] |
{
.name = "DENOISE",
.write = speex_write,
.read = speex_read
}
Definition at line 348 of file func_speex.c.
struct ast_datastore_info speex_datastore [static] |
{
.type = "speex",
.destroy = destroy_callback
}
Definition at line 135 of file func_speex.c.
1.6.2