static int i4l_startrec(struct ast_modem_pvt *p) { if (ast_modem_send(p, "AT+VRX+VTX", 0) || ast_modem_expect(p, "CONNECT", 5)) { ast_log(LOG_WARNING, "Unable to start recording\n"); return -1; } p->ministate = STATE_VOICE; /* let ast dsp detect dtmf */ if (p->dtmfmode & MODEM_DTMF_AST) { if (p->dsp) { ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", p->dev); } else { p->dsp = ast_dsp_new(); if (p->dsp) { ast_log(LOG_DEBUG, "Detecting DTMF inband with sw DSP on %s\n",p->dev); ast_dsp_set_features(p->dsp, DSP_FEATURE_DTMF_DETECT|DSP_FEATURE_FAX_DETECT); ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | 0); } } } return 0; }
static int i4l_answer(struct ast_modem_pvt *p) { if (ast_modem_send(p, "ATA\r", 4) || ast_modem_expect(p, "VCON", 10)) { ast_log(LOG_WARNING, "Unable to answer: %s", p->response); return -1; } #if 1 if (ast_modem_send(p, "AT+VDD=0,8", 0) || ast_modem_expect(p, "OK", 5)) { ast_log(LOG_WARNING, "Unable to set to phone line interface\n"); return -1; } #endif if (ast_modem_send(p, "AT+VTX+VRX", 0) || ast_modem_expect(p, "CONNECT", 10)) { ast_log(LOG_WARNING, "Unable to answer: %s", p->response); return -1; } p->ministate = STATE_VOICE; /* let ast dsp detect dtmf */ if (p->dtmfmode & MODEM_DTMF_AST) { if (p->dsp) { ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", p->dev); } else { p->dsp = ast_dsp_new(); if (p->dsp) { ast_log(LOG_DEBUG, "Detecting DTMF inband with sw DSP on %s\n",p->dev); ast_dsp_set_features(p->dsp, DSP_FEATURE_DTMF_DETECT|DSP_FEATURE_FAX_DETECT); ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | 0); } } } return 0; }
static int nv_detectfax_exec(struct ast_channel *chan, void *data) { int res = 0; struct ast_module_user *u; char tmp[256] = "\0"; char *p = NULL; char *waitstr = NULL; char *options = NULL; char *silstr = NULL; char *minstr = NULL; char *maxstr = NULL; struct ast_frame *fr = NULL; struct ast_frame *fr2 = NULL; int notsilent = 0; struct timeval start = {0, 0}, end = {0, 0}; int waitdur = 4; int sildur = 1000; int mindur = 100; int maxdur = -1; int skipanswer = 0; int noextneeded = 0; int ignoredtmf = 0; int ignorefax = 0; int ignoretalk = 0; int x = 0; int origrformat = 0; int features = 0; time_t timeout = 0; struct ast_dsp *dsp = NULL; pbx_builtin_setvar_helper(chan, "FAX_DETECTED", ""); pbx_builtin_setvar_helper(chan, "FAXEXTEN", ""); pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", ""); pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ""); if (data || !ast_strlen_zero((char *)data)) { strncpy(tmp, (char *)data, sizeof(tmp)-1); } p = tmp; waitstr = strsep(&p, "|"); options = strsep(&p, "|"); silstr = strsep(&p, "|"); minstr = strsep(&p, "|"); maxstr = strsep(&p, "|"); if (waitstr) { if ((sscanf(waitstr, "%d", &x) == 1) && (x > 0)) waitdur = x; } if (options) { if (strchr(options, 'n')) skipanswer = 1; if (strchr(options, 'x')) noextneeded = 1; if (strchr(options, 'd')) ignoredtmf = 1; if (strchr(options, 'f')) ignorefax = 1; if (strchr(options, 't')) ignoretalk = 1; } if (silstr) { if ((sscanf(silstr, "%d", &x) == 1) && (x > 0)) sildur = x; } if (minstr) { if ((sscanf(minstr, "%d", &x) == 1) && (x > 0)) mindur = x; } if (maxstr) { if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0)) maxdur = x; } ast_log(LOG_DEBUG, "Preparing detect of fax (waitdur=%ds, sildur=%dms, mindur=%dms, maxdur=%dms)\n", waitdur, sildur, mindur, maxdur); u = ast_module_user_add(chan); if (chan->_state != AST_STATE_UP && !skipanswer) { /* Otherwise answer unless we're supposed to send this while on-hook */ res = ast_answer(chan); } if (!res) { origrformat = chan->readformat; if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) ast_log(LOG_WARNING, "Unable to set read format to linear!\n"); } if (!(dsp = ast_dsp_new())) { ast_log(LOG_WARNING, "Unable to allocate DSP!\n"); res = -1; } if (dsp) { #if 0 if (!ignoretalk) ; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */ #endif if (!ignorefax) features |= DSP_FEATURE_FAX_DETECT; if (!ignoredtmf) features |= DSP_FEATURE_DTMF_DETECT; ast_dsp_set_threshold(dsp, 256); ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF); ast_dsp_digitmode(dsp, DSP_DIGITMODE_DTMF); } if (!res) { if (waitdur > 0) timeout = time(NULL) + (time_t)waitdur; while (ast_waitfor(chan, 50) > -1) { if (waitdur > 0 && time(NULL) > timeout) { res = 0; break; } fr = ast_read(chan); if (!fr) { ast_log(LOG_DEBUG, "Got hangup\n"); res = -1; break; } /* Duplicate frame because ast_dsp_process may free the frame passed */ fr2 = ast_frdup(fr); /* Do not pass channel to ast_dsp_process otherwise it may queue modified audio frame back */ fr2 = ast_dsp_process(NULL, dsp, fr2); if (!fr2) { ast_log(LOG_ERROR, "Bad DSP received (what happened?)\n"); ast_frfree(fr); res = 0; break; } if (fr2->frametype == AST_FRAME_DTMF) { if (fr2->subclass == 'f' && !ignorefax) { /* Fax tone -- Handle and return NULL */ ast_log(LOG_DEBUG, "Fax detected on %s\n", chan->name); if (strcmp(chan->exten, "fax")) { ast_log(LOG_NOTICE, "Redirecting '%s' to fax extension on context '%s'\n", chan->name, chan->context); pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1"); pbx_builtin_setvar_helper(chan, "FAXEXTEN", chan->exten); if (ast_exists_extension(chan, chan->context, "fax", 1, chan->CALLERID_FIELD)) { /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ strncpy(chan->exten, "fax", sizeof(chan->exten)-1); chan->priority = 0; } else ast_log(LOG_WARNING, "Fax detected, but no fax extension\n"); } else ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n"); res = 0; ast_frfree(fr); ast_frfree(fr2); break; } else if (!ignoredtmf) { ast_log(LOG_DEBUG, "DTMF detected on %s\n", chan->name); char t[2]; t[0] = fr2->subclass; t[1] = '\0'; if (noextneeded || ast_canmatch_extension(chan, chan->context, t, 1, chan->CALLERID_FIELD)) { pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1"); /* They entered a valid extension, or might be anyhow */ if (noextneeded) { ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n"); res = 0; } else { ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n"); res = fr2->subclass; } ast_frfree(fr); ast_frfree(fr2); break; } else ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n"); } } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) { int totalsilence; int ms; res = ast_dsp_silence(dsp, fr, &totalsilence); if (res && (totalsilence > sildur)) { /* We've been quiet a little while */ if (notsilent) { /* We had heard some talking */ gettimeofday(&end, NULL); ms = (end.tv_sec - start.tv_sec) * 1000; ms += (end.tv_usec - start.tv_usec) / 1000; ms -= sildur; if (ms < 0) ms = 0; if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) { char ms_str[10]; ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms); ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", chan->name); /* Save detected talk time (in milliseconds) */ sprintf(ms_str, "%d", ms); pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str); if (ast_exists_extension(chan, chan->context, "talk", 1, chan->CALLERID_FIELD)) { strncpy(chan->exten, "talk", sizeof(chan->exten) - 1); chan->priority = 0; } else ast_log(LOG_WARNING, "Talk detected, but no talk extension\n"); res = 0; ast_frfree(fr); ast_frfree(fr2); break; } else ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms); notsilent = 0; } } else { if (!notsilent) { /* Heard some audio, mark the begining of the token */ gettimeofday(&start, NULL); ast_log(LOG_DEBUG, "Start of voice token!\n"); notsilent = 1; } } } ast_frfree(fr); ast_frfree(fr2); } } else ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); if (res > -1) { if (origrformat && ast_set_read_format(chan, origrformat)) { ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", chan->name, ast_getformatname(origrformat)); } } if (dsp) ast_dsp_free(dsp); ast_module_user_remove(u); return res; }