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