Exemplo n.º 1
0
/*! \internal \brief Enable talk detection on the channel */
static int set_talk_detect(struct ast_channel *chan, int dsp_silence_threshold, int dsp_talking_threshold)
{
	struct ast_datastore *datastore = NULL;
	struct talk_detect_params *td_params;
	SCOPED_CHANNELLOCK(chan_lock, chan);

	datastore = ast_channel_datastore_find(chan, &talk_detect_datastore, NULL);
	if (!datastore) {
		datastore = ast_datastore_alloc(&talk_detect_datastore, NULL);
		if (!datastore) {
			return -1;
		}

		td_params = ast_calloc(1, sizeof(*td_params));
		if (!td_params) {
			ast_datastore_free(datastore);
			return -1;
		}

		ast_audiohook_init(&td_params->audiohook,
		                   AST_AUDIOHOOK_TYPE_MANIPULATE,
		                   "TALK_DETECT",
		                   AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
		td_params->audiohook.manipulate_callback = talk_detect_audiohook_cb;
		ast_set_flag(&td_params->audiohook, AST_AUDIOHOOK_TRIGGER_READ);

		td_params->dsp = ast_dsp_new_with_rate(ast_format_get_sample_rate(ast_channel_rawreadformat(chan)));
		if (!td_params->dsp) {
			ast_datastore_free(datastore);
			ast_free(td_params);
			return -1;
		}
		datastore->data = td_params;

		ast_channel_datastore_add(chan, datastore);
		ast_audiohook_attach(chan, &td_params->audiohook);
	} else {
		/* Talk detection already enabled; update existing settings */
		td_params = datastore->data;
	}

	td_params->dsp_talking_threshold = dsp_talking_threshold;
	td_params->dsp_silence_threshold = dsp_silence_threshold;

	ast_dsp_set_threshold(td_params->dsp, td_params->dsp_talking_threshold);

	return 0;
}
Exemplo n.º 2
0
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 int do_waiting(struct ast_channel *chan, int maxsilence) {

	struct ast_frame *f;
	int totalsilence = 0;
	int dspsilence = 0;
	int gotsilence = 0; 
	static int silencethreshold = 128;
	int rfmt = 0;
	int res = 0;
	struct ast_dsp *sildet;	 /* silence detector dsp */
	time_t start, now;
	time(&start);

	rfmt = chan->readformat; /* Set to linear mode */
	res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
	if (res < 0) {
		ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
		return -1;
	}

	sildet = ast_dsp_new(); /* Create the silence detector */
	if (!sildet) {
		ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
		return -1;
	}
	ast_dsp_set_threshold(sildet, silencethreshold);

	/* Await silence... */
	f = NULL;
	for(;;) {
		res = ast_waitfor(chan, 2000);
		if (!res) {
			ast_log(LOG_WARNING, "One waitfor failed, trying another\n");
			/* Try one more time in case of masq */
			res = ast_waitfor(chan, 2000);
			if (!res) {
				ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
				res = -1;
			}
		}

		if (res < 0) {
			f = NULL;
			break;
		}
		f = ast_read(chan);
		if (!f)
			break;
		if (f->frametype == AST_FRAME_VOICE) {
			dspsilence = 0;
			ast_dsp_silence(sildet, f, &dspsilence);
			if (dspsilence) {
				totalsilence = dspsilence;
				time(&start);
			} else {
				totalsilence = 0;
			}

			if (totalsilence >= maxsilence) {
				if (option_verbose > 2)
					ast_verbose(VERBOSE_PREFIX_3 "Exiting with %dms silence > %dms required\n", totalsilence, maxsilence);
				/* Ended happily with silence */
				gotsilence = 1;
				pbx_builtin_setvar_helper(chan, "WAITSTATUS", "SILENCE");
				ast_log(LOG_DEBUG, "WAITSTATUS was set to SILENCE\n");
				ast_frfree(f);
				break;
			} else if ( difftime(time(&now),start) >= maxsilence/1000 ) {
				pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT");
				ast_log(LOG_DEBUG, "WAITSTATUS was set to TIMEOUT\n");
				ast_frfree(f);
				break;
			}
		}
		ast_frfree(f);
	}
	if (rfmt && ast_set_read_format(chan, rfmt)) {
		ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
	}
	ast_dsp_free(sildet);
	return gotsilence;
}
Exemplo n.º 4
0
static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, int timeout, int wait_for_silence) {
	struct ast_frame *f = NULL;
	int dsptime = 0;
	struct ast_format rfmt;
	int res = 0;
	struct ast_dsp *sildet;	 /* silence detector dsp */
 	time_t now;

	/*Either silence or noise calc depending on wait_for_silence flag*/
	int (*ast_dsp_func)(struct ast_dsp*, struct ast_frame*, int*) =
				wait_for_silence ? ast_dsp_silence : ast_dsp_noise;

	ast_format_copy(&rfmt, &chan->readformat); /* Set to linear mode */
	if ((res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) < 0) {
		ast_log(LOG_WARNING, "Unable to set channel to linear mode, giving up\n");
		return -1;
	}

	/* Create the silence detector */
	if (!(sildet = ast_dsp_new())) {
		ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
		return -1;
	}
	ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));

	/* Await silence... */
	for (;;) {
		/* Start with no silence received */
		dsptime = 0;

		res = ast_waitfor(chan, timereqd);

		/* Must have gotten a hangup; let's exit */
		if (res < 0) {
			pbx_builtin_setvar_helper(chan, "WAITSTATUS", "HANGUP");
			break;
		}
		
		/* We waited and got no frame; sounds like digital silence or a muted digital channel */
		if (res == 0) {
			dsptime = timereqd;
		} else {
			/* Looks like we did get a frame, so let's check it out */
			if (!(f = ast_read(chan))) {
				pbx_builtin_setvar_helper(chan, "WAITSTATUS", "HANGUP");
				break;
			}
			if (f->frametype == AST_FRAME_VOICE) {
				ast_dsp_func(sildet, f, &dsptime);
			}
			ast_frfree(f);
		}

		ast_verb(6, "Got %dms %s < %dms required\n", dsptime, wait_for_silence ? "silence" : "noise", timereqd);

		if (dsptime >= timereqd) {
			ast_verb(3, "Exiting with %dms %s >= %dms required\n", dsptime, wait_for_silence ? "silence" : "noise", timereqd);
			/* Ended happily with silence */
			res = 1;
			pbx_builtin_setvar_helper(chan, "WAITSTATUS", wait_for_silence ? "SILENCE" : "NOISE");
			ast_debug(1, "WAITSTATUS was set to %s\n", wait_for_silence ? "SILENCE" : "NOISE");
			break;
		}

		if (timeout && (difftime(time(&now), waitstart) >= timeout)) {
			pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT");
			ast_debug(1, "WAITSTATUS was set to TIMEOUT\n");
			res = 0;
			break;
		}
	}


	if (rfmt.id && ast_set_read_format(chan, &rfmt)) {
		ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(&rfmt), chan->name);
	}
	ast_dsp_free(sildet);
	return res;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence)
{
    int d = 0;
    char *fmts;
    char comment[256];
    int x, fmtcnt=1, res=-1,outmsg=0;
    struct ast_frame *f;
    struct ast_filestream *others[MAX_OTHER_FORMATS];
    struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
    char *sfmt[MAX_OTHER_FORMATS];
    char *stringp=NULL;
    time_t start, end;
    struct ast_dsp *sildet;   	/* silence detector dsp */
    int totalsilence = 0;
    int dspsilence = 0;
    int gotsilence = 0;		/* did we timeout for silence? */
    int rfmt=0;
    char prependfile[80];

    if (silencethreshold < 0)
        silencethreshold = global_silence_threshold;

    if (maxsilence < 0)
        maxsilence = global_maxsilence;

    /* barf if no pointer passed to store duration in */
    if (duration == NULL) {
        ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
        return -1;
    }

    ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);

    if (playfile || beep) {
        if (!beep)
            d = ast_play_and_wait(chan, playfile);
        if (d > -1)
            d = ast_streamfile(chan, "beep",chan->language);
        if (!d)
            d = ast_waitstream(chan,"");
        if (d < 0)
            return -1;
    }
    strncpy(prependfile, recordfile, sizeof(prependfile) -1);
    strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);

    fmts = ast_strdupa(fmt);

    stringp=fmts;
    strsep(&stringp, "|");
    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
    sfmt[0] = ast_strdupa(fmts);

    while((fmt = strsep(&stringp, "|"))) {
        if (fmtcnt > MAX_OTHER_FORMATS - 1) {
            ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
            break;
        }
        sfmt[fmtcnt++] = ast_strdupa(fmt);
    }

    time(&start);
    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
    for (x=0; x<fmtcnt; x++) {
        others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
        ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
        if (!others[x]) {
            break;
        }
    }

    sildet = ast_dsp_new(); /* Create the silence detector */
    if (!sildet) {
        ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
        return -1;
    }
    ast_dsp_set_threshold(sildet, silencethreshold);

    if (maxsilence > 0) {
        rfmt = chan->readformat;
        res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
        if (res < 0) {
            ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
            return -1;
        }
    }

    if (x == fmtcnt) {
        /* Loop forever, writing the packets we read to the writer(s), until
           we read a # or get a hangup */
        f = NULL;
        for(;;) {
            res = ast_waitfor(chan, 2000);
            if (!res) {
                ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
                /* Try one more time in case of masq */
                res = ast_waitfor(chan, 2000);
                if (!res) {
                    ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
                    res = -1;
                }
            }

            if (res < 0) {
                f = NULL;
                break;
            }
            f = ast_read(chan);
            if (!f)
                break;
            if (f->frametype == AST_FRAME_VOICE) {
                /* write each format */
                for (x=0; x<fmtcnt; x++) {
                    if (!others[x])
                        break;
                    res = ast_writestream(others[x], f);
                }

                /* Silence Detection */
                if (maxsilence > 0) {
                    dspsilence = 0;
                    ast_dsp_silence(sildet, f, &dspsilence);
                    if (dspsilence)
                        totalsilence = dspsilence;
                    else
                        totalsilence = 0;

                    if (totalsilence > maxsilence) {
                        /* Ended happily with silence */
                        if (option_verbose > 2)
                            ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
                        ast_frfree(f);
                        gotsilence = 1;
                        outmsg=2;
                        break;
                    }
                }
                /* Exit on any error */
                if (res) {
                    ast_log(LOG_WARNING, "Error writing frame\n");
                    ast_frfree(f);
                    break;
                }
            } else if (f->frametype == AST_FRAME_VIDEO) {
                /* Write only once */
                ast_writestream(others[0], f);
            } else if (f->frametype == AST_FRAME_DTMF) {
                /* stop recording with any digit */
                if (option_verbose > 2)
                    ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
                res = 't';
                outmsg = 2;
                ast_frfree(f);
                break;
            }
            if (maxtime) {
                time(&end);
                if (maxtime < (end - start)) {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
                    res = 't';
                    outmsg=2;
                    ast_frfree(f);
                    break;
                }
            }
            ast_frfree(f);
        }
        if (end == start) time(&end);
        if (!f) {
            if (option_verbose > 2)
                ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
            res = -1;
            outmsg=1;
#if 0
            /* delete all the prepend files */
            for (x=0; x<fmtcnt; x++) {
                if (!others[x])
                    break;
                ast_closestream(others[x]);
                ast_filedelete(prependfile, sfmt[x]);
            }
#endif
        }
    } else {
        ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
    }
    *duration = end - start;
#if 0
    if (outmsg > 1) {
#else
    if (outmsg) {
#endif
        struct ast_frame *fr;
        for (x=0; x<fmtcnt; x++) {
            snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
            realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
            if (!others[x] || !realfiles[x])
                break;
            if (totalsilence)
                ast_stream_rewind(others[x], totalsilence-200);
            else
                ast_stream_rewind(others[x], 200);
            ast_truncstream(others[x]);
            /* add the original file too */
            while ((fr = ast_readframe(realfiles[x]))) {
                ast_writestream(others[x],fr);
            }
            ast_closestream(others[x]);
            ast_closestream(realfiles[x]);
            ast_filerename(prependfile, recordfile, sfmt[x]);
#if 0
            ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
#endif
            ast_filedelete(prependfile, sfmt[x]);
        }
    }
    if (rfmt) {
        if (ast_set_read_format(chan, rfmt)) {
            ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
        }
    }
    if (outmsg) {
        if (outmsg > 1) {
            /* Let them know it worked */
            ast_streamfile(chan, "auth-thankyou", chan->language);
            ast_waitstream(chan, "");
        }
    }
    return res;
}

int ast_lock_path(const char *path)
{
    char *s;
    char *fs;
    int res;
    int fd;
    time_t start;
    s = alloca(strlen(path) + 10);
    fs = alloca(strlen(path) + 20);
    if (!fs || !s) {
        ast_log(LOG_WARNING, "Out of memory!\n");
        return -1;
    }
    snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand());
    fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
    if (fd < 0) {
        fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno));
        return -1;
    }
    close(fd);
    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
    time(&start);
    while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
        usleep(1);
    if (res < 0) {
        ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
    }
    unlink(fs);
    ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
    return res;
}
Exemplo n.º 7
0
int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
{
    char *fmts;
    int d;
    char comment[256];
    int x, fmtcnt=1, res=-1,outmsg=0;
    struct ast_frame *f;
    struct ast_filestream *others[MAX_OTHER_FORMATS];
    char *sfmt[MAX_OTHER_FORMATS];
    char *stringp=NULL;
    time_t start, end;
    struct ast_dsp *sildet=NULL;   	/* silence detector dsp */
    int totalsilence = 0;
    int dspsilence = 0;
    int gotsilence = 0;		/* did we timeout for silence? */
    int rfmt=0;

    if (silencethreshold < 0)
        silencethreshold = global_silence_threshold;

    if (maxsilence < 0)
        maxsilence = global_maxsilence;

    /* barf if no pointer passed to store duration in */
    if (duration == NULL) {
        ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
        return -1;
    }

    ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);

    if (playfile) {
        d = ast_play_and_wait(chan, playfile);
        if (d > -1)
            d = ast_streamfile(chan, "beep",chan->language);
        if (!d)
            d = ast_waitstream(chan,"");
        if (d < 0)
            return -1;
    }

    fmts = ast_strdupa(fmt);

    stringp=fmts;
    strsep(&stringp, "|");
    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
    sfmt[0] = ast_strdupa(fmts);

    while((fmt = strsep(&stringp, "|"))) {
        if (fmtcnt > MAX_OTHER_FORMATS - 1) {
            ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
            break;
        }
        sfmt[fmtcnt++] = ast_strdupa(fmt);
    }

    time(&start);
    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
    for (x=0; x<fmtcnt; x++) {
        others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
        ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);

        if (!others[x]) {
            break;
        }
    }

    if (path)
        ast_unlock_path(path);


    if (maxsilence > 0) {
        sildet = ast_dsp_new(); /* Create the silence detector */
        if (!sildet) {
            ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
            return -1;
        }
        ast_dsp_set_threshold(sildet, silencethreshold);
        rfmt = chan->readformat;
        res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
        if (res < 0) {
            ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
            ast_dsp_free(sildet);
            return -1;
        }
    }

    if (x == fmtcnt) {
        /* Loop forever, writing the packets we read to the writer(s), until
           we read a # or get a hangup */
        f = NULL;
        for(;;) {
            res = ast_waitfor(chan, 2000);
            if (!res) {
                ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
                /* Try one more time in case of masq */
                res = ast_waitfor(chan, 2000);
                if (!res) {
                    ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
                    res = -1;
                }
            }

            if (res < 0) {
                f = NULL;
                break;
            }
            f = ast_read(chan);
            if (!f)
                break;
            if (f->frametype == AST_FRAME_VOICE) {
                /* write each format */
                for (x=0; x<fmtcnt; x++) {
                    res = ast_writestream(others[x], f);
                }

                /* Silence Detection */
                if (maxsilence > 0) {
                    dspsilence = 0;
                    ast_dsp_silence(sildet, f, &dspsilence);
                    if (dspsilence)
                        totalsilence = dspsilence;
                    else
                        totalsilence = 0;

                    if (totalsilence > maxsilence) {
                        /* Ended happily with silence */
                        if (option_verbose > 2)
                            ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
                        ast_frfree(f);
                        gotsilence = 1;
                        outmsg=2;
                        break;
                    }
                }
                /* Exit on any error */
                if (res) {
                    ast_log(LOG_WARNING, "Error writing frame\n");
                    ast_frfree(f);
                    break;
                }
            } else if (f->frametype == AST_FRAME_VIDEO) {
                /* Write only once */
                ast_writestream(others[0], f);
            } else if (f->frametype == AST_FRAME_DTMF) {
                if (f->subclass == '#') {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
                    res = '#';
                    outmsg = 2;
                    ast_frfree(f);
                    break;
                }
            }
            if (f->subclass == '0') {
                /* Check for a '0' during message recording also, in case caller wants operator */
                if (option_verbose > 2)
                    ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
                res = '0';
                outmsg = 0;
                ast_frfree(f);
                break;
            }
            if (maxtime) {
                time(&end);
                if (maxtime < (end - start)) {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
                    outmsg = 2;
                    res = 't';
                    ast_frfree(f);
                    break;
                }
            }
            ast_frfree(f);
        }
        if (end == start) time(&end);
        if (!f) {
            if (option_verbose > 2)
                ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
            res = -1;
            outmsg=1;
        }
    } else {
        ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
    }

    *duration = end - start;

    for (x=0; x<fmtcnt; x++) {
        if (!others[x])
            break;
        if (res > 0) {
            if (totalsilence)
                ast_stream_rewind(others[x], totalsilence-200);
            else
                ast_stream_rewind(others[x], 200);
        }
        ast_truncstream(others[x]);
        ast_closestream(others[x]);
    }
    if (rfmt) {
        if (ast_set_read_format(chan, rfmt)) {
            ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
        }
    }
    if (outmsg > 1) {
        /* Let them know recording is stopped */
        if(!ast_streamfile(chan, "auth-thankyou", chan->language))
            ast_waitstream(chan, "");
    }
    if (sildet)
        ast_dsp_free(sildet);
    return res;
}
Exemplo n.º 8
0
static int do_waiting(struct ast_channel *chan, int silencereqd, time_t waitstart, int timeout) {
	struct ast_frame *f;
	int dspsilence = 0;
	static int silencethreshold = 128;
	int rfmt = 0;
	int res = 0;
	struct ast_dsp *sildet;	 /* silence detector dsp */
 	time_t now;

	rfmt = chan->readformat; /* Set to linear mode */
	res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
	if (res < 0) {
		ast_log(LOG_WARNING, "Unable to set channel to linear mode, giving up\n");
		return -1;
	}

	sildet = ast_dsp_new(); /* Create the silence detector */
	if (!sildet) {
		ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
		return -1;
	}
	ast_dsp_set_threshold(sildet, silencethreshold);

	/* Await silence... */
	f = NULL;
	for(;;) {
		/* Start with no silence received */
		dspsilence = 0;

		res = ast_waitfor(chan, silencereqd);

		/* Must have gotten a hangup; let's exit */
		if (res < 0) {
			f = NULL;
			break;
		}
		
		/* We waited and got no frame; sounds like digital silence or a muted digital channel */
		if (res == 0) {
			dspsilence = silencereqd;
		} else {
			/* Looks like we did get a frame, so let's check it out */
			f = ast_read(chan);
			if (!f)
				break;
			if (f && f->frametype == AST_FRAME_VOICE) {
				ast_dsp_silence(sildet, f, &dspsilence);
			}
			if (f) {
				ast_frfree(f);
			}
		}

		if (option_verbose > 6)
			ast_verbose(VERBOSE_PREFIX_3 "Got %dms silence< %dms required\n", dspsilence, silencereqd);

		if (dspsilence >= silencereqd) {
			if (option_verbose > 2)
				ast_verbose(VERBOSE_PREFIX_3 "Exiting with %dms silence >= %dms required\n", dspsilence, silencereqd);
			/* Ended happily with silence */
			res = 1;
			pbx_builtin_setvar_helper(chan, "WAITSTATUS", "SILENCE");
			ast_log(LOG_DEBUG, "WAITSTATUS was set to SILENCE\n");
			break;
		}

		if ( timeout && (difftime(time(&now),waitstart) >= timeout) ) {
			pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT");
			ast_log(LOG_DEBUG, "WAITSTATUS was set to TIMEOUT\n");
			res = 0;
			break;
		}
	}


	if (rfmt && ast_set_read_format(chan, rfmt)) {
		ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
	}
	ast_dsp_free(sildet);
	return res;
}
static int record_exec(struct ast_channel *chan, void *data)
{
	int res = 0;
	int count = 0;
	int percentflag = 0;
	char *filename, *ext = NULL, *silstr, *maxstr, *options;
	char *vdata, *p;
	int i = 0;
	char tmp[256];

	struct ast_filestream *s = '\0';
	struct localuser *u;
	struct ast_frame *f = NULL;
	
	struct ast_dsp *sildet = NULL;   	/* silence detector dsp */
	int totalsilence = 0;
	int dspsilence = 0;
	int silence = 0;		/* amount of silence to allow */
	int gotsilence = 0;		/* did we timeout for silence? */
	int maxduration = 0;		/* max duration of recording in milliseconds */
	int gottimeout = 0;		/* did we timeout for maxduration exceeded? */
	int option_skip = 0;
	int option_noanswer = 0;
	int option_append = 0;
	int terminator = '#';
	int option_quiet = 0;
	int rfmt = 0;
	int flags;
	int waitres;
	struct ast_silence_generator *silgen = NULL;
	
	/* The next few lines of code parse out the filename and header from the input string */
	if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */
		ast_log(LOG_WARNING, "Record requires an argument (filename)\n");
		return -1;
	}

	LOCAL_USER_ADD(u);

	/* Yay for strsep being easy */
	vdata = ast_strdupa(data);
	if (!vdata) {
		ast_log(LOG_ERROR, "Out of memory\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}

	p = vdata;
	filename = strsep(&p, "|");
	silstr = strsep(&p, "|");
	maxstr = strsep(&p, "|");	
	options = strsep(&p, "|");
	
	if (filename) {
		if (strstr(filename, "%d"))
			percentflag = 1;
		ext = strrchr(filename, '.'); /* to support filename with a . in the filename, not format */
		if (!ext)
			ext = strchr(filename, ':');
		if (ext) {
			*ext = '\0';
			ext++;
		}
	}
	if (!ext) {
		ast_log(LOG_WARNING, "No extension specified to filename!\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}
	if (silstr) {
		if ((sscanf(silstr, "%d", &i) == 1) && (i > -1)) {
			silence = i * 1000;
		} else if (!ast_strlen_zero(silstr)) {
			ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", silstr);
		}
	}
	
	if (maxstr) {
		if ((sscanf(maxstr, "%d", &i) == 1) && (i > -1))
			/* Convert duration to milliseconds */
			maxduration = i * 1000;
		else if (!ast_strlen_zero(maxstr))
			ast_log(LOG_WARNING, "'%s' is not a valid maximum duration\n", maxstr);
	}
	if (options) {
		/* Retain backwards compatibility with old style options */
		if (!strcasecmp(options, "skip"))
			option_skip = 1;
		else if (!strcasecmp(options, "noanswer"))
			option_noanswer = 1;
		else {
			if (strchr(options, 's'))
				option_skip = 1;
			if (strchr(options, 'n'))
				option_noanswer = 1;
			if (strchr(options, 'a'))
				option_append = 1;
			if (strchr(options, 't'))
				terminator = '*';
			if (strchr(options, 'q'))
				option_quiet = 1;
		}
	}
	
	/* done parsing */
	
	/* these are to allow the use of the %d in the config file for a wild card of sort to
	  create a new file with the inputed name scheme */
	if (percentflag) {
		do {
			snprintf(tmp, sizeof(tmp), filename, count);
			count++;
		} while ( ast_fileexists(tmp, ext, chan->language) != -1 );
		pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp);
	} else
		strncpy(tmp, filename, sizeof(tmp)-1);
	/* end of routine mentioned */
	
	
	
	if (chan->_state != AST_STATE_UP) {
		if (option_skip) {
			/* At the user's option, skip if the line is not up */
			LOCAL_USER_REMOVE(u);
			return 0;
		} else if (!option_noanswer) {
			/* Otherwise answer unless we're supposed to record while on-hook */
			res = ast_answer(chan);
		}
	}
	
	if (res) {
		ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
		goto out;
	}
	
	if (!option_quiet) {
		/* Some code to play a nice little beep to signify the start of the record operation */
		res = ast_streamfile(chan, "beep", chan->language);
		if (!res) {
			res = ast_waitstream(chan, "");
		} else {
			ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", chan->name);
		}
		ast_stopstream(chan);
	}
		
	/* The end of beep code.  Now the recording starts */
		
	if (silence > 0) {
		rfmt = chan->readformat;
		res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
		if (res < 0) {
			ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
			LOCAL_USER_REMOVE(u);
			return -1;
		}
		sildet = ast_dsp_new();
		if (!sildet) {
			ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
			LOCAL_USER_REMOVE(u);
			return -1;
		}
		ast_dsp_set_threshold(sildet, 256);
	} 
		
		
	flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY;
	s = ast_writefile( tmp, ext, NULL, flags , 0, 0644);
		
	if (!s) {
		ast_log(LOG_WARNING, "Could not create file %s\n", filename);
		goto out;
	}

	if (option_transmit_silence_during_record)
		silgen = ast_channel_start_silence_generator(chan);
	
	/* Request a video update */
	ast_indicate(chan, AST_CONTROL_VIDUPDATE);
	
	if (maxduration <= 0)
		maxduration = -1;
	
	while ((waitres = ast_waitfor(chan, maxduration)) > -1) {
		if (maxduration > 0) {
			if (waitres == 0) {
				gottimeout = 1;
				break;
			}
			maxduration = waitres;
		}
		
		f = ast_read(chan);
		if (!f) {
			res = -1;
			break;
		}
		if (f->frametype == AST_FRAME_VOICE) {
			res = ast_writestream(s, f);
			
			if (res) {
				ast_log(LOG_WARNING, "Problem writing frame\n");
				ast_frfree(f);
				break;
			}
			
			if (silence > 0) {
				dspsilence = 0;
				ast_dsp_silence(sildet, f, &dspsilence);
				if (dspsilence) {
					totalsilence = dspsilence;
				} else {
					totalsilence = 0;
				}
				if (totalsilence > silence) {
					/* Ended happily with silence */
					ast_frfree(f);
					gotsilence = 1;
					break;
				}
			}
		} else if (f->frametype == AST_FRAME_VIDEO) {
			res = ast_writestream(s, f);
			
			if (res) {
				ast_log(LOG_WARNING, "Problem writing frame\n");
				ast_frfree(f);
				break;
			}
		} else if ((f->frametype == AST_FRAME_DTMF) &&
		    (f->subclass == terminator)) {
			ast_frfree(f);
			break;
		}
		ast_frfree(f);
	}
	if (!f) {
		ast_log(LOG_DEBUG, "Got hangup\n");
		res = -1;
	}
			
	if (gotsilence) {
		ast_stream_rewind(s, silence-1000);
		ast_truncstream(s);
	} else if (!gottimeout) {
		/* Strip off the last 1/4 second of it */
		ast_stream_rewind(s, 250);
		ast_truncstream(s);
	}
	ast_closestream(s);

	if (silgen)
		ast_channel_stop_silence_generator(chan, silgen);
	
 out:
	if ((silence > 0) && rfmt) {
		res = ast_set_read_format(chan, rfmt);
		if (res)
			ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
		if (sildet)
			ast_dsp_free(sildet);
	}

	LOCAL_USER_REMOVE(u);

	return res;
}