static int nv_detectfax_exec(struct ast_channel *chan, const char *data) { int res = 0; 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; struct ast_format* origrformat = NULL; int features = 0; time_t timeout = 0; struct ast_dsp *dsp = NULL; struct ast_format_cap *cap; struct ast_format linearFormat; /* linear format capabilities */ ast_format_set(&linearFormat, AST_FORMAT_SLINEAR, 0); cap = ast_format_cap_alloc_nolock(); ast_format_cap_add(cap, &linearFormat); /* done */ 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(data)) { strncpy(tmp, 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=%dms, sildur=%dms, mindur=%dms, maxdur=%dms)\n", waitdur, sildur, mindur, maxdur); // LOCAL_USER_ADD(u); // if (chan->_state != AST_STATE_UP && !skipanswer) { if (ast_channel_state(chan) != 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; origrformat = ast_channel_readformat(chan); // if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) if ((res = ast_set_read_format_from_cap(chan, cap)) ){ 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 (!ignoretalk) ; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */ if (!ignorefax) features |= DSP_FEATURE_FAX_DETECT; //if (!ignoredtmf) features |= DSP_FEATURE_DIGIT_DETECT; ast_dsp_set_threshold(dsp, 256); ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF); ast_dsp_set_digitmode(dsp, DSP_DIGITMODE_DTMF); } if (!res) { if (waitdur > 0) timeout = time(NULL) + (time_t)waitdur; while(ast_waitfor(chan, -1) > -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; } fr2 = ast_dsp_process(chan, dsp, fr); if (!fr2) { ast_log(LOG_WARNING, "Bad DSP received (what happened?)\n"); fr2 = fr; } if (fr2->frametype == AST_FRAME_DTMF) { if (fr2->subclass.integer == 'f' && !ignorefax) { /* Fax tone -- Handle and return NULL */ ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan)); ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan)); if (strcmp(ast_channel_exten(chan), "fax")) { ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", ast_channel_name(chan)); pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1"); pbx_builtin_setvar_helper(chan,"FAXEXTEN",ast_channel_exten(chan)); if (ast_exists_extension(chan, ast_channel_context(chan), "fax", 1, ast_channel_caller(chan)->id.number.str)) { /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ // strncpy(ast_channel_exten(chan), "fax", sizeof(ast_channel_exten(chan))-1); // chan->priority = 0; ast_channel_exten_set(chan, "fax"); ast_channel_priority_set(chan, 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); break; } else if (!ignoredtmf) { ast_log(LOG_DEBUG, "DTMF detected on %s\n", ast_channel_name(chan)); char t[2]; t[0] = fr2->subclass.integer; t[1] = '\0'; if (noextneeded || ast_canmatch_extension(chan, ast_channel_context(chan), t, 1, ast_channel_caller(chan)->id.number.str)) { 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.integer; } ast_frfree(fr); 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) { } else if ((fr->frametype == AST_FRAME_VOICE) && ( ast_format_cap_iscompatible(cap, &fr->subclass.format)) && !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", ast_channel_name(chan)); /* 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, ast_channel_context(chan), "talk", 1, ast_channel_caller(chan)->id.number.str)) { // strncpy(ast_channel_exten(chan), "talk", sizeof(ast_channel_exten(chan)) - 1); // chan->priority = 0; ast_channel_exten_set(chan, "talk"); ast_channel_priority_set(chan, 0); } else ast_log(LOG_WARNING, "Talk detected, but no talk extension\n"); res = 0; ast_frfree(fr); 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); } } else ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(chan)); 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", ast_channel_name(chan), ast_getformatname(origrformat)); } } if (dsp) ast_dsp_free(dsp); // LOCAL_USER_REMOVE(u); ast_format_cap_destroy(cap); return res; }
static struct ast_frame *i4l_read(struct ast_modem_pvt *p) { unsigned char result[256]; short *b; struct ast_frame *f=NULL; int res; int x; if (p->ministate == STATE_COMMAND) { /* Read the first two bytes, first, in case it's a control message */ res = read(p->fd, result, 2); if (res < 2) { /* short read, means there was a hangup? */ /* (or is this also possible without hangup?) */ /* Anyway, reading from unitialized buffers is a bad idea anytime. */ if (errno == EAGAIN) return i4l_handle_escape(p, 0); return NULL; } if (result[0] == CHAR_DLE) { return i4l_handle_escape(p, result[1]); } else { if ((result[0] == '\n') || (result[0] == '\r')) return i4l_handle_escape(p, 0); /* Read the rest of the line */ fgets(result + 2, sizeof(result) - 2, p->f); ast_modem_trim(result); if (!strcasecmp(result, "VCON")) { /* If we're in immediate mode, reply now */ /* if (p->mode == MODEM_MODE_IMMEDIATE) */ return i4l_handle_escape(p, 'X'); } else if (!strcasecmp(result, "BUSY")) { /* Same as a busy signal */ return i4l_handle_escape(p, 'b'); } else if (!strncasecmp(result, "CALLER NUMBER: ", 15 )) { strncpy(p->cid_num, result + 15, sizeof(p->cid_num)-1); return i4l_handle_escape(p, 0); } else if (!strcasecmp(result, "RINGING")) { if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "%s is ringing...\n", p->dev); return i4l_handle_escape(p, 'I'); } else if (!strncasecmp(result, "RUNG", 4)) { /* PM2002: the line was hung up before we picked it up, bye bye */ if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "%s was hung up on before we answered\n", p->dev); return NULL; } else if (!strncasecmp(result, "RING", 4)) { if (result[4]=='/') strncpy(p->dnid, result + 5, sizeof(p->dnid)-1); return i4l_handle_escape(p, 'R'); } else if (!strcasecmp(result, "NO CARRIER")) { if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "%s hung up on\n", p->dev); return NULL; } else if (!strcasecmp(result, "NO DIALTONE")) { /* There's no dialtone, so the line isn't working */ ast_log(LOG_WARNING, "Device '%s' lacking dialtone\n", p->dev); return NULL; } if (option_debug) ast_log(LOG_DEBUG, "Modem said '%s'\n", result); return i4l_handle_escape(p, 0); } } else { /* We have to be more efficient in voice mode */ b = (short *)(p->obuf + p->obuflen); while (p->obuflen/2 < 240) { /* Read ahead the full amount */ res = read(p->fd, result, 240 - p->obuflen/2); if (res < 1) { /* If there's nothing there, just continue on */ if (errno == EAGAIN) return i4l_handle_escape(p, 0); ast_log(LOG_WARNING, "Read failed: %s\n", strerror(errno)); return NULL; } for (x=0; x<res; x++) { /* Process all the bytes that we've read */ switch(result[x]) { case CHAR_DLE: #if 0 ast_log(LOG_DEBUG, "Ooh, an escape at %d...\n", x); #endif if (!p->escape) { /* Note that next value is an escape, and continue. */ p->escape++; break; } else { /* Send as is -- fallthrough */ p->escape = 0; } default: if (p->escape) { ast_log(LOG_DEBUG, "Value of escape is %c (%d)...\n", result[x] < 32 ? '^' : result[x], result[x]); p->escape = 0; if (f) ast_log(LOG_WARNING, "Warning: Dropped a signal frame\n"); f = i4l_handle_escape(p, result[x]); /* If i4l_handle_escape says NULL, say it now, doesn't matter what else is there, the connection is dead. */ if (!f) return NULL; } else { *(b++) = AST_MULAW((int)result[x]); p->obuflen += 2; } } } if (f) break; } if (f) { if( ! (!(p->dtmfmode & MODEM_DTMF_I4L) && f->frametype == AST_FRAME_DTMF)) return f; } /* If we get here, we have a complete voice frame */ p->fr.frametype = AST_FRAME_VOICE; p->fr.subclass = AST_FORMAT_SLINEAR; p->fr.samples = 240; p->fr.data = p->obuf; p->fr.datalen = p->obuflen; p->fr.mallocd = 0; p->fr.delivery.tv_sec = 0; p->fr.delivery.tv_usec = 0; p->fr.offset = AST_FRIENDLY_OFFSET; p->fr.src = __FUNCTION__; p->obuflen = 0; /* process with dsp */ if (p->dsp) { f = ast_dsp_process(p->owner, p->dsp, &p->fr); if (f && (f->frametype == AST_FRAME_DTMF)) { ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c on %s\n", f->subclass, p->dev); if (f->subclass == 'f') { /* Fax tone -- Handle and return NULL */ struct ast_channel *ast = p->owner; if (!p->faxhandled) { p->faxhandled++; if (strcmp(ast->exten, "fax")) { const char *target_context = ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext; if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) { if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name); /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten); if (ast_async_goto(ast, target_context, "fax", 1)) ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context); } else ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); } else ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n"); } else ast_log(LOG_DEBUG, "Fax already handled\n"); p->fr.frametype = AST_FRAME_NULL; p->fr.subclass = 0; f = &p->fr; } return f; } } return &p->fr; } return NULL; }
static int transmit_audio(fax_session *s) { int res = -1; int original_read_fmt = AST_FORMAT_SLINEAR; int original_write_fmt = AST_FORMAT_SLINEAR; fax_state_t fax; struct ast_dsp *dsp = NULL; int detect_tone = 0; struct ast_frame *inf = NULL; struct ast_frame *fr; int last_state = 0; struct timeval now, start, state_change; enum ast_control_t38 t38control; original_read_fmt = s->chan->readformat; if (original_read_fmt != AST_FORMAT_SLINEAR) { res = ast_set_read_format(s->chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); goto done; } } original_write_fmt = s->chan->writeformat; if (original_write_fmt != AST_FORMAT_SLINEAR) { res = ast_set_write_format(s->chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); goto done; } } /* Initialize T30 terminal */ fax_init(&fax, s->caller_mode); /* Setup logging */ set_logging(&fax.logging); set_logging(&fax.t30_state.logging); /* Configure terminal */ set_local_info(&fax.t30_state, s); set_file(&fax.t30_state, s); set_ecm(&fax.t30_state, TRUE); fax_set_transmit_on_idle(&fax, TRUE); t30_set_phase_e_handler(&fax.t30_state, phase_e_handler, s); if (s->t38state == T38_STATE_UNAVAILABLE) { ast_debug(1, "T38 is unavailable on %s\n", s->chan->name); } else if (!s->direction) { /* We are receiving side and this means we are the side which should request T38 when the fax is detected. Use DSP to detect fax tone */ ast_debug(1, "Setting up CNG detection on %s\n", s->chan->name); dsp = ast_dsp_new(); ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT); ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG); detect_tone = 1; } start = state_change = ast_tvnow(); ast_activate_generator(s->chan, &generator, &fax); while (!s->finished) { res = ast_waitfor(s->chan, 20); if (res < 0) break; else if (res > 0) res = 0; inf = ast_read(s->chan); if (inf == NULL) { ast_debug(1, "Channel hangup\n"); res = -1; break; } ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen); /* Detect fax tone */ if (detect_tone && inf->frametype == AST_FRAME_VOICE) { /* Duplicate frame because ast_dsp_process may free the frame passed */ fr = ast_frdup(inf); /* Do not pass channel to ast_dsp_process otherwise it may queue modified audio frame back */ fr = ast_dsp_process(NULL, dsp, fr); if (fr && fr->frametype == AST_FRAME_DTMF && fr->subclass == 'f') { ast_debug(1, "Fax tone detected. Requesting T38\n"); t38control = AST_T38_REQUEST_NEGOTIATE; ast_indicate_data(s->chan, AST_CONTROL_T38, &t38control, sizeof(t38control)); detect_tone = 0; } ast_frfree(fr); } /* Check the frame type. Format also must be checked because there is a chance that a frame in old format was already queued before we set chanel format to slinear so it will still be received by ast_read */ if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) { if (fax_rx(&fax, inf->data, inf->samples) < 0) { /* I know fax_rx never returns errors. The check here is for good style only */ ast_log(LOG_WARNING, "fax_rx returned error\n"); res = -1; break; } /* Watchdog */ if (last_state != fax.t30_state.state) { state_change = ast_tvnow(); last_state = fax.t30_state.state; } } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 && inf->datalen == sizeof(enum ast_control_t38)) { t38control =*((enum ast_control_t38 *) inf->data); if (t38control == AST_T38_NEGOTIATED) { /* T38 switchover completed */ ast_debug(1, "T38 negotiated, finishing audio loop\n"); res = 1; break; } } ast_frfree(inf); inf = NULL; /* Watchdog */ now = ast_tvnow(); if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) { ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n"); res = -1; break; } } ast_debug(1, "Loop finished, res=%d\n", res); if (inf) ast_frfree(inf); if (dsp) ast_dsp_free(dsp); ast_deactivate_generator(s->chan); /* If we are switching to T38, remove phase E handler. Otherwise it will be executed by t30_terminate, display diagnostics and set status variables although no transmittion has taken place yet. */ if (res > 0) { t30_set_phase_e_handler(&fax.t30_state, NULL, NULL); } t30_terminate(&fax.t30_state); fax_release(&fax); done: if (original_write_fmt != AST_FORMAT_SLINEAR) { if (ast_set_write_format(s->chan, original_write_fmt) < 0) ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", s->chan->name); } if (original_read_fmt != AST_FORMAT_SLINEAR) { if (ast_set_read_format(s->chan, original_read_fmt) < 0) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", s->chan->name); } return res; }
static int nv_background_detect_exec(struct ast_channel *chan, void *data) { int res = 0; struct ast_module_user *u; char tmp[256] = "\0"; char *p = NULL; char *filename = 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 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; 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)) { ast_log(LOG_WARNING, "NVBackgroundDetect requires an argument (filename)\n"); return -1; } strncpy(tmp, (char *)data, sizeof(tmp)-1); p = tmp; filename = strsep(&p, "|"); options = strsep(&p, "|"); silstr = strsep(&p, "|"); minstr = strsep(&p, "|"); maxstr = strsep(&p, "|"); 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 '%s' (sildur=%dms, mindur=%dms, maxdur=%dms)\n", tmp, 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 (!ignoretalk) ; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */ 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) { ast_stopstream(chan); res = ast_streamfile(chan, tmp, chan->language); if (!res) { while(chan->stream) { res = ast_sched_wait(chan->sched); if ((res < 0) && !chan->timingfunc) { res = 0; break; } if (res < 0) res = 1000; res = ast_waitfor(chan, res); if (res < 0) { ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name); break; } else if (res > 0) { fr = ast_read(chan); if (!fr) { ast_log(LOG_DEBUG, "Got hangup\n"); res = -1; break; } fr2 = ast_dsp_process(chan, dsp, fr); if (!fr2) { ast_log(LOG_WARNING, "Bad DSP received (what happened?)\n"); fr2 = fr; } 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\n", chan->name); 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); break; } else if (!ignoredtmf) { char t[2]; t[0] = fr2->subclass; t[1] = '\0'; ast_log(LOG_DEBUG, "DTMF detected on %s\n", chan->name); 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); 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); 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_sched_runq(chan->sched); } ast_stopstream(chan); } else { ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data); res = 0; } } 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; }