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: 232359 $")
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 iTotalTime += framelength;
00279 if (iTotalTime >= totalAnalysisTime) {
00280 ast_verb(3, "AMD: Channel [%s]. Too long...\n", chan->name );
00281 ast_frfree(f);
00282 strcpy(amdStatus , "NOTSURE");
00283 sprintf(amdCause , "TOOLONG-%d", iTotalTime);
00284 break;
00285 }
00286
00287
00288 if (f->frametype != AST_FRAME_VOICE)
00289 dspsilence += 2 * maxWaitTimeForFrame;
00290 else {
00291 dspsilence = 0;
00292 ast_dsp_silence(silenceDetector, f, &dspsilence);
00293 }
00294
00295 if (dspsilence > 0) {
00296 silenceDuration = dspsilence;
00297
00298 if (silenceDuration >= betweenWordsSilence) {
00299 if (currentState != STATE_IN_SILENCE ) {
00300 previousState = currentState;
00301 ast_verb(3, "AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", chan->name);
00302 }
00303
00304 if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){
00305 ast_verb(3, "AMD: Channel [%s]. Short Word Duration: %d\n", chan->name, consecutiveVoiceDuration);
00306 }
00307 currentState = STATE_IN_SILENCE;
00308 consecutiveVoiceDuration = 0;
00309 }
00310
00311 if (inInitialSilence == 1 && silenceDuration >= initialSilence) {
00312 ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
00313 chan->name, silenceDuration, initialSilence);
00314 ast_frfree(f);
00315 strcpy(amdStatus , "MACHINE");
00316 sprintf(amdCause , "INITIALSILENCE-%d-%d", silenceDuration, initialSilence);
00317 res = 1;
00318 break;
00319 }
00320
00321 if (silenceDuration >= afterGreetingSilence && inGreeting == 1) {
00322 ast_verb(3, "AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
00323 chan->name, silenceDuration, afterGreetingSilence);
00324 ast_frfree(f);
00325 strcpy(amdStatus , "HUMAN");
00326 sprintf(amdCause , "HUMAN-%d-%d", silenceDuration, afterGreetingSilence);
00327 res = 1;
00328 break;
00329 }
00330
00331 } else {
00332 consecutiveVoiceDuration += framelength;
00333 voiceDuration += framelength;
00334
00335
00336
00337 if (consecutiveVoiceDuration >= minimumWordLength && currentState == STATE_IN_SILENCE) {
00338 iWordsCount++;
00339 ast_verb(3, "AMD: Channel [%s]. Word detected. iWordsCount:%d\n", chan->name, iWordsCount);
00340 previousState = currentState;
00341 currentState = STATE_IN_WORD;
00342 }
00343 if (consecutiveVoiceDuration >= maximumWordLength){
00344 ast_verb(3, "AMD: Channel [%s]. Maximum Word Length detected. [%d]\n", chan->name, consecutiveVoiceDuration);
00345 ast_frfree(f);
00346 strcpy(amdStatus , "MACHINE");
00347 sprintf(amdCause , "MAXWORDLENGTH-%d", consecutiveVoiceDuration);
00348 break;
00349 }
00350 if (iWordsCount >= maximumNumberOfWords) {
00351 ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", chan->name, iWordsCount);
00352 ast_frfree(f);
00353 strcpy(amdStatus , "MACHINE");
00354 sprintf(amdCause , "MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords);
00355 res = 1;
00356 break;
00357 }
00358
00359 if (inGreeting == 1 && voiceDuration >= greeting) {
00360 ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", chan->name, voiceDuration, greeting);
00361 ast_frfree(f);
00362 strcpy(amdStatus , "MACHINE");
00363 sprintf(amdCause , "LONGGREETING-%d-%d", voiceDuration, greeting);
00364 res = 1;
00365 break;
00366 }
00367
00368 if (voiceDuration >= minimumWordLength ) {
00369 if (silenceDuration > 0)
00370 ast_verb(3, "AMD: Channel [%s]. Detected Talk, previous silence duration: %d\n", chan->name, silenceDuration);
00371 silenceDuration = 0;
00372 }
00373 if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0) {
00374
00375 if (silenceDuration > 0)
00376 ast_verb(3, "AMD: Channel [%s]. Before Greeting Time: silenceDuration: %d voiceDuration: %d\n", chan->name, silenceDuration, voiceDuration);
00377 inInitialSilence = 0;
00378 inGreeting = 1;
00379 }
00380
00381 }
00382 }
00383 ast_frfree(f);
00384 }
00385
00386 if (!res) {
00387
00388 ast_verb(3, "AMD: Channel [%s]. Too long...\n", chan->name);
00389 strcpy(amdStatus , "NOTSURE");
00390 sprintf(amdCause , "TOOLONG-%d", iTotalTime);
00391 }
00392
00393
00394 pbx_builtin_setvar_helper(chan , "AMDSTATUS" , amdStatus);
00395 pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause);
00396
00397
00398 if (readFormat && ast_set_read_format(chan, readFormat))
00399 ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", chan->name);
00400
00401
00402 ast_dsp_free(silenceDetector);
00403
00404 return;
00405 }
00406
00407
00408 static int amd_exec(struct ast_channel *chan, void *data)
00409 {
00410 isAnsweringMachine(chan, data);
00411
00412 return 0;
00413 }
00414
00415 static int load_config(int reload)
00416 {
00417 struct ast_config *cfg = NULL;
00418 char *cat = NULL;
00419 struct ast_variable *var = NULL;
00420 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00421
00422 dfltSilenceThreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
00423
00424 if (!(cfg = ast_config_load("amd.conf", config_flags))) {
00425 ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n");
00426 return -1;
00427 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00428 return 0;
00429 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00430 ast_log(LOG_ERROR, "Config file amd.conf is in an invalid format. Aborting.\n");
00431 return -1;
00432 }
00433
00434 cat = ast_category_browse(cfg, NULL);
00435
00436 while (cat) {
00437 if (!strcasecmp(cat, "general") ) {
00438 var = ast_variable_browse(cfg, cat);
00439 while (var) {
00440 if (!strcasecmp(var->name, "initial_silence")) {
00441 dfltInitialSilence = atoi(var->value);
00442 } else if (!strcasecmp(var->name, "greeting")) {
00443 dfltGreeting = atoi(var->value);
00444 } else if (!strcasecmp(var->name, "after_greeting_silence")) {
00445 dfltAfterGreetingSilence = atoi(var->value);
00446 } else if (!strcasecmp(var->name, "silence_threshold")) {
00447 dfltSilenceThreshold = atoi(var->value);
00448 } else if (!strcasecmp(var->name, "total_analysis_time")) {
00449 dfltTotalAnalysisTime = atoi(var->value);
00450 } else if (!strcasecmp(var->name, "min_word_length")) {
00451 dfltMinimumWordLength = atoi(var->value);
00452 } else if (!strcasecmp(var->name, "between_words_silence")) {
00453 dfltBetweenWordsSilence = atoi(var->value);
00454 } else if (!strcasecmp(var->name, "maximum_number_of_words")) {
00455 dfltMaximumNumberOfWords = atoi(var->value);
00456 } else if (!strcasecmp(var->name, "maximum_word_length")) {
00457 dfltMaximumWordLength = atoi(var->value);
00458
00459 } else {
00460 ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n",
00461 app, cat, var->name, var->lineno);
00462 }
00463 var = var->next;
00464 }
00465 }
00466 cat = ast_category_browse(cfg, cat);
00467 }
00468
00469 ast_config_destroy(cfg);
00470
00471 ast_verb(3, "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
00472 "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d]\n",
00473 dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime,
00474 dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold, dfltMaximumWordLength);
00475
00476 return 0;
00477 }
00478
00479 static int unload_module(void)
00480 {
00481 return ast_unregister_application(app);
00482 }
00483
00484 static int load_module(void)
00485 {
00486 if (load_config(0))
00487 return AST_MODULE_LOAD_DECLINE;
00488 if (ast_register_application_xml(app, amd_exec))
00489 return AST_MODULE_LOAD_FAILURE;
00490 return AST_MODULE_LOAD_SUCCESS;
00491 }
00492
00493 static int reload(void)
00494 {
00495 if (load_config(1))
00496 return AST_MODULE_LOAD_DECLINE;
00497 return AST_MODULE_LOAD_SUCCESS;
00498 }
00499
00500 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Answering Machine Detection Application",
00501 .load = load_module,
00502 .unload = unload_module,
00503 .reload = reload,
00504 );