00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include "asterisk.h"
00041
00042 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 366169 $")
00043
00044 #include <speex/speex_preprocess.h>
00045 #include "asterisk/module.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/pbx.h"
00048 #include "asterisk/utils.h"
00049 #include "asterisk/audiohook.h"
00050
00051 #define DEFAULT_AGC_LEVEL 8000.0
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099 struct speex_direction_info {
00100 SpeexPreprocessState *state;
00101 int agc;
00102 int denoise;
00103 int samples;
00104 float agclevel;
00105 };
00106
00107 struct speex_info {
00108 struct ast_audiohook audiohook;
00109 int lastrate;
00110 struct speex_direction_info *tx, *rx;
00111 };
00112
00113 static void destroy_callback(void *data)
00114 {
00115 struct speex_info *si = data;
00116
00117 ast_audiohook_destroy(&si->audiohook);
00118
00119 if (si->rx && si->rx->state) {
00120 speex_preprocess_state_destroy(si->rx->state);
00121 }
00122
00123 if (si->tx && si->tx->state) {
00124 speex_preprocess_state_destroy(si->tx->state);
00125 }
00126
00127 if (si->rx) {
00128 ast_free(si->rx);
00129 }
00130
00131 if (si->tx) {
00132 ast_free(si->tx);
00133 }
00134
00135 ast_free(data);
00136 };
00137
00138 static const struct ast_datastore_info speex_datastore = {
00139 .type = "speex",
00140 .destroy = destroy_callback
00141 };
00142
00143 static int speex_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
00144 {
00145 struct ast_datastore *datastore = NULL;
00146 struct speex_direction_info *sdi = NULL;
00147 struct speex_info *si = NULL;
00148 char source[80];
00149
00150
00151 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || frame->frametype != AST_FRAME_VOICE) {
00152 return -1;
00153 }
00154
00155
00156 if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
00157 return -1;
00158 }
00159
00160 si = datastore->data;
00161
00162 sdi = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? si->rx : si->tx;
00163
00164 if (!sdi) {
00165 return -1;
00166 }
00167
00168 if ((sdi->samples != frame->samples) || (ast_format_rate(&frame->subclass.format) != si->lastrate)) {
00169 si->lastrate = ast_format_rate(&frame->subclass.format);
00170 if (sdi->state) {
00171 speex_preprocess_state_destroy(sdi->state);
00172 }
00173
00174 if (!(sdi->state = speex_preprocess_state_init((sdi->samples = frame->samples), si->lastrate))) {
00175 return -1;
00176 }
00177
00178 speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC, &sdi->agc);
00179
00180 if (sdi->agc) {
00181 speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &sdi->agclevel);
00182 }
00183
00184 speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_DENOISE, &sdi->denoise);
00185 }
00186
00187 speex_preprocess(sdi->state, frame->data.ptr, NULL);
00188 snprintf(source, sizeof(source), "%s/speex", frame->src);
00189 if (frame->mallocd & AST_MALLOCD_SRC) {
00190 ast_free((char *) frame->src);
00191 }
00192 frame->src = ast_strdup(source);
00193 frame->mallocd |= AST_MALLOCD_SRC;
00194
00195 return 0;
00196 }
00197
00198 static int speex_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00199 {
00200 struct ast_datastore *datastore = NULL;
00201 struct speex_info *si = NULL;
00202 struct speex_direction_info **sdi = NULL;
00203 int is_new = 0;
00204
00205 if (strcasecmp(data, "rx") && strcasecmp(data, "tx")) {
00206 ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
00207 return -1;
00208 }
00209
00210 ast_channel_lock(chan);
00211 if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
00212 ast_channel_unlock(chan);
00213
00214 if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) {
00215 return 0;
00216 }
00217
00218 if (!(si = ast_calloc(1, sizeof(*si)))) {
00219 ast_datastore_free(datastore);
00220 return 0;
00221 }
00222
00223 ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
00224 si->audiohook.manipulate_callback = speex_callback;
00225 si->lastrate = 8000;
00226 is_new = 1;
00227 } else {
00228 ast_channel_unlock(chan);
00229 si = datastore->data;
00230 }
00231
00232 if (!strcasecmp(data, "rx")) {
00233 sdi = &si->rx;
00234 } else {
00235 sdi = &si->tx;
00236 }
00237
00238 if (!*sdi) {
00239 if (!(*sdi = ast_calloc(1, sizeof(**sdi)))) {
00240 return 0;
00241 }
00242
00243
00244
00245 (*sdi)->samples = -1;
00246 }
00247
00248 if (!strcasecmp(cmd, "agc")) {
00249 if (!sscanf(value, "%30f", &(*sdi)->agclevel))
00250 (*sdi)->agclevel = ast_true(value) ? DEFAULT_AGC_LEVEL : 0.0;
00251
00252 if ((*sdi)->agclevel > 32768.0) {
00253 ast_log(LOG_WARNING, "AGC(%s)=%.01f is greater than 32768... setting to 32768 instead\n",
00254 ((*sdi == si->rx) ? "rx" : "tx"), (*sdi)->agclevel);
00255 (*sdi)->agclevel = 32768.0;
00256 }
00257
00258 (*sdi)->agc = !!((*sdi)->agclevel);
00259
00260 if ((*sdi)->state) {
00261 speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC, &(*sdi)->agc);
00262 if ((*sdi)->agc) {
00263 speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &(*sdi)->agclevel);
00264 }
00265 }
00266 } else if (!strcasecmp(cmd, "denoise")) {
00267 (*sdi)->denoise = (ast_true(value) != 0);
00268
00269 if ((*sdi)->state) {
00270 speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_DENOISE, &(*sdi)->denoise);
00271 }
00272 }
00273
00274 if (!(*sdi)->agc && !(*sdi)->denoise) {
00275 if ((*sdi)->state)
00276 speex_preprocess_state_destroy((*sdi)->state);
00277
00278 ast_free(*sdi);
00279 *sdi = NULL;
00280 }
00281
00282 if (!si->rx && !si->tx) {
00283 if (is_new) {
00284 is_new = 0;
00285 } else {
00286 ast_channel_lock(chan);
00287 ast_channel_datastore_remove(chan, datastore);
00288 ast_channel_unlock(chan);
00289 ast_audiohook_remove(chan, &si->audiohook);
00290 ast_audiohook_detach(&si->audiohook);
00291 }
00292
00293 ast_datastore_free(datastore);
00294 }
00295
00296 if (is_new) {
00297 datastore->data = si;
00298 ast_channel_lock(chan);
00299 ast_channel_datastore_add(chan, datastore);
00300 ast_channel_unlock(chan);
00301 ast_audiohook_attach(chan, &si->audiohook);
00302 }
00303
00304 return 0;
00305 }
00306
00307 static int speex_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00308 {
00309 struct ast_datastore *datastore = NULL;
00310 struct speex_info *si = NULL;
00311 struct speex_direction_info *sdi = NULL;
00312
00313 if (!chan) {
00314 ast_log(LOG_ERROR, "%s cannot be used without a channel!\n", cmd);
00315 return -1;
00316 }
00317
00318 ast_channel_lock(chan);
00319 if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
00320 ast_channel_unlock(chan);
00321 return -1;
00322 }
00323 ast_channel_unlock(chan);
00324
00325 si = datastore->data;
00326
00327 if (!strcasecmp(data, "tx"))
00328 sdi = si->tx;
00329 else if (!strcasecmp(data, "rx"))
00330 sdi = si->rx;
00331 else {
00332 ast_log(LOG_ERROR, "%s(%s) must either \"tx\" or \"rx\"\n", cmd, data);
00333 return -1;
00334 }
00335
00336 if (!strcasecmp(cmd, "agc"))
00337 snprintf(buf, len, "%.01f", sdi ? sdi->agclevel : 0.0);
00338 else
00339 snprintf(buf, len, "%d", sdi ? sdi->denoise : 0);
00340
00341 return 0;
00342 }
00343
00344 static struct ast_custom_function agc_function = {
00345 .name = "AGC",
00346 .write = speex_write,
00347 .read = speex_read,
00348 .read_max = 22,
00349 };
00350
00351 static struct ast_custom_function denoise_function = {
00352 .name = "DENOISE",
00353 .write = speex_write,
00354 .read = speex_read,
00355 .read_max = 22,
00356 };
00357
00358 static int unload_module(void)
00359 {
00360 ast_custom_function_unregister(&agc_function);
00361 ast_custom_function_unregister(&denoise_function);
00362 return 0;
00363 }
00364
00365 static int load_module(void)
00366 {
00367 if (ast_custom_function_register(&agc_function)) {
00368 return AST_MODULE_LOAD_DECLINE;
00369 }
00370
00371 if (ast_custom_function_register(&denoise_function)) {
00372 ast_custom_function_unregister(&agc_function);
00373 return AST_MODULE_LOAD_DECLINE;
00374 }
00375
00376 return AST_MODULE_LOAD_SUCCESS;
00377 }
00378
00379 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Noise reduction and Automatic Gain Control (AGC)");