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 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 277188 $")
00033
00034 #include "asterisk/module.h"
00035 #include "asterisk/lock.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/dsp.h"
00038 #include "asterisk/pbx.h"
00039 #include "asterisk/config.h"
00040 #include "asterisk/app.h"
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
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
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 static char *app = "AMD";
00128
00129 #define STATE_IN_WORD 1
00130 #define STATE_IN_SILENCE 2
00131
00132
00133 static int dfltInitialSilence = 2500;
00134 static int dfltGreeting = 1500;
00135 static int dfltAfterGreetingSilence = 800;
00136 static int dfltTotalAnalysisTime = 5000;
00137 static int dfltMinimumWordLength = 100;
00138 static int dfltBetweenWordsSilence = 50;
00139 static int dfltMaximumNumberOfWords = 3;
00140 static int dfltSilenceThreshold = 256;
00141 static int dfltMaximumWordLength = 5000;
00142
00143
00144 static int dfltMaxWaitTimeForFrame = 50;
00145
00146 static void isAnsweringMachine(struct ast_channel *chan, void *data)
00147 {
00148 int res = 0;
00149 struct ast_frame *f = NULL;
00150 struct ast_dsp *silenceDetector = NULL;
00151 int dspsilence = 0, readFormat, framelength = 0;
00152 int inInitialSilence = 1;
00153 int inGreeting = 0;
00154 int voiceDuration = 0;
00155 int silenceDuration = 0;
00156 int iTotalTime = 0;
00157 int iWordsCount = 0;
00158 int currentState = STATE_IN_WORD;
00159 int previousState = STATE_IN_SILENCE;
00160 int consecutiveVoiceDuration = 0;
00161 char amdCause[256] = "", amdStatus[256] = "";
00162 char *parse = ast_strdupa(data);
00163
00164
00165
00166
00167
00168 int initialSilence = dfltInitialSilence;
00169 int greeting = dfltGreeting;
00170 int afterGreetingSilence = dfltAfterGreetingSilence;
00171 int totalAnalysisTime = dfltTotalAnalysisTime;
00172 int minimumWordLength = dfltMinimumWordLength;
00173 int betweenWordsSilence = dfltBetweenWordsSilence;
00174 int maximumNumberOfWords = dfltMaximumNumberOfWords;
00175 int silenceThreshold = dfltSilenceThreshold;
00176 int maximumWordLength = dfltMaximumWordLength;
00177 int maxWaitTimeForFrame = dfltMaxWaitTimeForFrame;
00178
00179 AST_DECLARE_APP_ARGS(args,
00180 AST_APP_ARG(argInitialSilence);
00181 AST_APP_ARG(argGreeting);
00182 AST_APP_ARG(argAfterGreetingSilence);
00183 AST_APP_ARG(argTotalAnalysisTime);
00184 AST_APP_ARG(argMinimumWordLength);
00185 AST_APP_ARG(argBetweenWordsSilence);
00186 AST_APP_ARG(argMaximumNumberOfWords);
00187 AST_APP_ARG(argSilenceThreshold);
00188 AST_APP_ARG(argMaximumWordLength);
00189 );
00190
00191 ast_verb(3, "AMD: %s %s %s (Fmt: %d)\n", chan->name ,chan->cid.cid_ani, chan->cid.cid_rdnis, chan->readformat);
00192
00193
00194 if (!ast_strlen_zero(parse)) {
00195
00196 AST_STANDARD_APP_ARGS(args, parse);
00197 if (!ast_strlen_zero(args.argInitialSilence))
00198 initialSilence = atoi(args.argInitialSilence);
00199 if (!ast_strlen_zero(args.argGreeting))
00200 greeting = atoi(args.argGreeting);
00201 if (!ast_strlen_zero(args.argAfterGreetingSilence))
00202 afterGreetingSilence = atoi(args.argAfterGreetingSilence);
00203 if (!ast_strlen_zero(args.argTotalAnalysisTime))
00204 totalAnalysisTime = atoi(args.argTotalAnalysisTime);
00205 if (!ast_strlen_zero(args.argMinimumWordLength))
00206 minimumWordLength = atoi(args.argMinimumWordLength);
00207 if (!ast_strlen_zero(args.argBetweenWordsSilence))
00208 betweenWordsSilence = atoi(args.argBetweenWordsSilence);
00209 if (!ast_strlen_zero(args.argMaximumNumberOfWords))
00210 maximumNumberOfWords = atoi(args.argMaximumNumberOfWords);
00211 if (!ast_strlen_zero(args.argSilenceThreshold))
00212 silenceThreshold = atoi(args.argSilenceThreshold);
00213 if (!ast_strlen_zero(args.argMaximumWordLength))
00214 maximumWordLength = atoi(args.argMaximumWordLength);
00215 } else {
00216 ast_debug(1, "AMD using the default parameters.\n");
00217 }
00218
00219
00220 if (maxWaitTimeForFrame > initialSilence)
00221 maxWaitTimeForFrame = initialSilence;
00222 if (maxWaitTimeForFrame > greeting)
00223 maxWaitTimeForFrame = greeting;
00224 if (maxWaitTimeForFrame > afterGreetingSilence)
00225 maxWaitTimeForFrame = afterGreetingSilence;
00226 if (maxWaitTimeForFrame > totalAnalysisTime)
00227 maxWaitTimeForFrame = totalAnalysisTime;
00228 if (maxWaitTimeForFrame > minimumWordLength)
00229 maxWaitTimeForFrame = minimumWordLength;
00230 if (maxWaitTimeForFrame > betweenWordsSilence)
00231 maxWaitTimeForFrame = betweenWordsSilence;
00232
00233
00234 ast_verb(3, "AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
00235 "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d] \n",
00236 initialSilence, greeting, afterGreetingSilence, totalAnalysisTime,
00237 minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold, maximumWordLength);
00238
00239
00240 readFormat = chan->readformat;
00241 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0 ) {
00242 ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to set to linear mode, giving up\n", chan->name );
00243 pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
00244 pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
00245 return;
00246 }
00247
00248
00249 if (!(silenceDetector = ast_dsp_new())) {
00250 ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to create silence detector :(\n", chan->name );
00251 pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
00252 pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
00253 return;
00254 }
00255
00256
00257 ast_dsp_set_threshold(silenceDetector, silenceThreshold);
00258
00259
00260 while ((res = ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) {
00261
00262
00263 if (!(f = ast_read(chan))) {
00264 ast_verb(3, "AMD: Channel [%s]. HANGUP\n", chan->name);
00265 ast_debug(1, "Got hangup\n");
00266 strcpy(amdStatus, "HANGUP");
00267 res = 1;
00268 break;
00269 }
00270
00271 if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_NULL || f->frametype == AST_FRAME_CNG) {
00272
00273 if (f->frametype == AST_FRAME_VOICE) {
00274 framelength = (ast_codec_get_samples(f) / DEFAULT_SAMPLES_PER_MS);
00275 } else {
00276 framelength = 2 * maxWaitTimeForFrame;
00277 }
00278
00279 iTotalTime += framelength;
00280 if (iTotalTime >= totalAnalysisTime) {
00281 ast_verb(3, "AMD: Channel [%s]. Too long...\n", chan->name );
00282 ast_frfree(f);
00283 strcpy(amdStatus , "NOTSURE");
00284 sprintf(amdCause , "TOOLONG-%d", iTotalTime);
00285 break;
00286 }
00287
00288
00289 if (f->frametype != AST_FRAME_VOICE)
00290 dspsilence += 2 * maxWaitTimeForFrame;
00291 else {
00292 dspsilence = 0;
00293 ast_dsp_silence(silenceDetector, f, &dspsilence);
00294 }
00295
00296 if (dspsilence > 0) {
00297 silenceDuration = dspsilence;
00298
00299 if (silenceDuration >= betweenWordsSilence) {
00300 if (currentState != STATE_IN_SILENCE ) {
00301 previousState = currentState;
00302 ast_verb(3, "AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", chan->name);
00303 }
00304
00305 if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){
00306 ast_verb(3, "AMD: Channel [%s]. Short Word Duration: %d\n", chan->name, consecutiveVoiceDuration);
00307 }
00308 currentState = STATE_IN_SILENCE;
00309 consecutiveVoiceDuration = 0;
00310 }
00311
00312 if (inInitialSilence == 1 && silenceDuration >= initialSilence) {
00313 ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
00314 chan->name, silenceDuration, initialSilence);
00315 ast_frfree(f);
00316 strcpy(amdStatus , "MACHINE");
00317 sprintf(amdCause , "INITIALSILENCE-%d-%d", silenceDuration, initialSilence);
00318 res = 1;
00319 break;
00320 }
00321
00322 if (silenceDuration >= afterGreetingSilence && inGreeting == 1) {
00323 ast_verb(3, "AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
00324 chan->name, silenceDuration, afterGreetingSilence);
00325 ast_frfree(f);
00326 strcpy(amdStatus , "HUMAN");
00327 sprintf(amdCause , "HUMAN-%d-%d", silenceDuration, afterGreetingSilence);
00328 res = 1;
00329 break;
00330 }
00331
00332 } else {
00333 consecutiveVoiceDuration += framelength;
00334 voiceDuration += framelength;
00335
00336
00337
00338 if (consecutiveVoiceDuration >= minimumWordLength && currentState == STATE_IN_SILENCE) {
00339 iWordsCount++;
00340 ast_verb(3, "AMD: Channel [%s]. Word detected. iWordsCount:%d\n", chan->name, iWordsCount);
00341 previousState = currentState;
00342 currentState = STATE_IN_WORD;
00343 }
00344 if (consecutiveVoiceDuration >= maximumWordLength){
00345 ast_verb(3, "AMD: Channel [%s]. Maximum Word Length detected. [%d]\n", chan->name, consecutiveVoiceDuration);
00346 ast_frfree(f);
00347 strcpy(amdStatus , "MACHINE");
00348 sprintf(amdCause , "MAXWORDLENGTH-%d", consecutiveVoiceDuration);
00349 break;
00350 }
00351 if (iWordsCount >= maximumNumberOfWords) {
00352 ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", chan->name, iWordsCount);
00353 ast_frfree(f);
00354 strcpy(amdStatus , "MACHINE");
00355 sprintf(amdCause , "MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords);
00356 res = 1;
00357 break;
00358 }
00359
00360 if (inGreeting == 1 && voiceDuration >= greeting) {
00361 ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", chan->name, voiceDuration, greeting);
00362 ast_frfree(f);
00363 strcpy(amdStatus , "MACHINE");
00364 sprintf(amdCause , "LONGGREETING-%d-%d", voiceDuration, greeting);
00365 res = 1;
00366 break;
00367 }
00368
00369 if (voiceDuration >= minimumWordLength ) {
00370 if (silenceDuration > 0)
00371 ast_verb(3, "AMD: Channel [%s]. Detected Talk, previous silence duration: %d\n", chan->name, silenceDuration);
00372 silenceDuration = 0;
00373 }
00374 if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0) {
00375
00376 if (silenceDuration > 0)
00377 ast_verb(3, "AMD: Channel [%s]. Before Greeting Time: silenceDuration: %d voiceDuration: %d\n", chan->name, silenceDuration, voiceDuration);
00378 inInitialSilence = 0;
00379 inGreeting = 1;
00380 }
00381
00382 }
00383 }
00384 ast_frfree(f);
00385 }
00386
00387 if (!res) {
00388
00389 ast_verb(3, "AMD: Channel [%s]. Too long...\n", chan->name);
00390 strcpy(amdStatus , "NOTSURE");
00391 sprintf(amdCause , "TOOLONG-%d", iTotalTime);
00392 }
00393
00394
00395 pbx_builtin_setvar_helper(chan , "AMDSTATUS" , amdStatus);
00396 pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause);
00397
00398
00399 if (readFormat && ast_set_read_format(chan, readFormat))
00400 ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", chan->name);
00401
00402
00403 ast_dsp_free(silenceDetector);
00404
00405 return;
00406 }
00407
00408
00409 static int amd_exec(struct ast_channel *chan, void *data)
00410 {
00411 isAnsweringMachine(chan, data);
00412
00413 return 0;
00414 }
00415
00416 static int load_config(int reload)
00417 {
00418 struct ast_config *cfg = NULL;
00419 char *cat = NULL;
00420 struct ast_variable *var = NULL;
00421 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00422
00423 dfltSilenceThreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
00424
00425 if (!(cfg = ast_config_load("amd.conf", config_flags))) {
00426 ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n");
00427 return -1;
00428 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00429 return 0;
00430 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00431 ast_log(LOG_ERROR, "Config file amd.conf is in an invalid format. Aborting.\n");
00432 return -1;
00433 }
00434
00435 cat = ast_category_browse(cfg, NULL);
00436
00437 while (cat) {
00438 if (!strcasecmp(cat, "general") ) {
00439 var = ast_variable_browse(cfg, cat);
00440 while (var) {
00441 if (!strcasecmp(var->name, "initial_silence")) {
00442 dfltInitialSilence = atoi(var->value);
00443 } else if (!strcasecmp(var->name, "greeting")) {
00444 dfltGreeting = atoi(var->value);
00445 } else if (!strcasecmp(var->name, "after_greeting_silence")) {
00446 dfltAfterGreetingSilence = atoi(var->value);
00447 } else if (!strcasecmp(var->name, "silence_threshold")) {
00448 dfltSilenceThreshold = atoi(var->value);
00449 } else if (!strcasecmp(var->name, "total_analysis_time")) {
00450 dfltTotalAnalysisTime = atoi(var->value);
00451 } else if (!strcasecmp(var->name, "min_word_length")) {
00452 dfltMinimumWordLength = atoi(var->value);
00453 } else if (!strcasecmp(var->name, "between_words_silence")) {
00454 dfltBetweenWordsSilence = atoi(var->value);
00455 } else if (!strcasecmp(var->name, "maximum_number_of_words")) {
00456 dfltMaximumNumberOfWords = atoi(var->value);
00457 } else if (!strcasecmp(var->name, "maximum_word_length")) {
00458 dfltMaximumWordLength = atoi(var->value);
00459
00460 } else {
00461 ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n",
00462 app, cat, var->name, var->lineno);
00463 }
00464 var = var->next;
00465 }
00466 }
00467 cat = ast_category_browse(cfg, cat);
00468 }
00469
00470 ast_config_destroy(cfg);
00471
00472 ast_verb(3, "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
00473 "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d]\n",
00474 dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime,
00475 dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold, dfltMaximumWordLength);
00476
00477 return 0;
00478 }
00479
00480 static int unload_module(void)
00481 {
00482 return ast_unregister_application(app);
00483 }
00484
00485 static int load_module(void)
00486 {
00487 if (load_config(0))
00488 return AST_MODULE_LOAD_DECLINE;
00489 if (ast_register_application_xml(app, amd_exec))
00490 return AST_MODULE_LOAD_FAILURE;
00491 return AST_MODULE_LOAD_SUCCESS;
00492 }
00493
00494 static int reload(void)
00495 {
00496 if (load_config(1))
00497 return AST_MODULE_LOAD_DECLINE;
00498 return AST_MODULE_LOAD_SUCCESS;
00499 }
00500
00501 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Answering Machine Detection Application",
00502 .load = load_module,
00503 .unload = unload_module,
00504 .reload = reload,
00505 );