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: 328209 $")
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 struct speex_direction_info *tx, *rx;
00110 };
00111
00112 static void destroy_callback(void *data)
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 };
00136
00137 static const struct ast_datastore_info speex_datastore = {
00138 .type = "speex",
00139 .destroy = destroy_callback
00140 };
00141
00142 static int speex_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
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
00150 if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || frame->frametype != AST_FRAME_VOICE) {
00151 return -1;
00152 }
00153
00154
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 }
00195
00196 static int speex_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
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 ast_channel_lock(chan);
00204 if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
00205 ast_channel_unlock(chan);
00206
00207 if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) {
00208 return 0;
00209 }
00210
00211 if (!(si = ast_calloc(1, sizeof(*si)))) {
00212 ast_datastore_free(datastore);
00213 return 0;
00214 }
00215
00216 ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex");
00217 si->audiohook.manipulate_callback = speex_callback;
00218
00219 is_new = 1;
00220 } else {
00221 ast_channel_unlock(chan);
00222 si = datastore->data;
00223 }
00224
00225 if (!strcasecmp(data, "rx")) {
00226 sdi = &si->rx;
00227 } else if (!strcasecmp(data, "tx")) {
00228 sdi = &si->tx;
00229 } else {
00230 ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
00231
00232 if (is_new) {
00233 ast_datastore_free(datastore);
00234 return -1;
00235 }
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)");