示例#1
0
文件: app_test.c 项目: GGGO/asterisk
static int measurenoise(struct ast_channel *chan, int ms, char *who)
{
	int res=0;
	int mssofar;
	int noise=0;
	int samples=0;
	int x;
	short *foo;
	struct timeval start;
	struct ast_frame *f;
	struct ast_format *rformat;

	rformat = ao2_bump(ast_channel_readformat(chan));
	if (ast_set_read_format(chan, ast_format_slin)) {
		ast_log(LOG_NOTICE, "Unable to set to linear mode!\n");
		ao2_cleanup(rformat);
		return -1;
	}
	start = ast_tvnow();
	for(;;) {
		mssofar = ast_tvdiff_ms(ast_tvnow(), start);
		if (mssofar > ms)
			break;
		res = ast_waitfor(chan, ms - mssofar);
		if (res < 1)
			break;
		f = ast_read(chan);
		if (!f) {
			res = -1;
			break;
		}
		if ((f->frametype == AST_FRAME_VOICE) &&
			(ast_format_cmp(f->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) {
			foo = (short *)f->data.ptr;
			for (x=0;x<f->samples;x++) {
				noise += abs(foo[x]);
				samples++;
			}
		}
		ast_frfree(f);
	}

	if (rformat) {
		if (ast_set_read_format(chan, rformat)) {
			ast_log(LOG_NOTICE, "Unable to restore original format!\n");
			ao2_ref(rformat, -1);
			return -1;
		}
		ao2_ref(rformat, -1);
	}
	if (res < 0)
		return res;
	if (!samples) {
		ast_log(LOG_NOTICE, "No samples were received from the other side!\n");
		return -1;
	}
	ast_debug(1, "%s: Noise: %d, samples: %d, avg: %d\n", who, noise, samples, noise / samples);
	return (noise / samples);
}
示例#2
0
int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
{
	unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL };
	int msglens[5];
	int msgtypes[5];
	int newdatamode;
	int res;
	int x;
	int writeformat, readformat;

	writeformat = chan->writeformat;
	readformat = chan->readformat;

	newdatamode = chan->adsicpe & ADSI_FLAG_DATAMODE;

	for (x=0;x<msglen;x+=(msg[x+1]+2)) {
		if (msg[x] == ADSI_SWITCH_TO_DATA) 
			newdatamode = ADSI_FLAG_DATAMODE;
		
		if (msg[x] == ADSI_SWITCH_TO_VOICE)
			newdatamode = 0;
	}
	msgs[0] = msg;

	msglens[0] = msglen;
	msgtypes[0] = msgtype;

	if (msglen > 253) {
		ast_log(LOG_WARNING, "Can't send ADSI message of %d bytes, too large\n", msglen);
		return -1;
	}

	ast_stopstream(chan);

	if (ast_set_write_format(chan, AST_FORMAT_ULAW)) {
		ast_log(LOG_WARNING, "Unable to set write format to ULAW\n");
		return -1;
	}

	if (ast_set_read_format(chan, AST_FORMAT_ULAW)) {
		ast_log(LOG_WARNING, "Unable to set read format to ULAW\n");
		if (writeformat) {
			if (ast_set_write_format(chan, writeformat)) 
				ast_log(LOG_WARNING, "Unable to restore write format to %d\n", writeformat);
		}
		return -1;
	}
	res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes);
	if (!res)
		chan->adsicpe = (chan->adsicpe & ~ADSI_FLAG_DATAMODE) | newdatamode;

	if (writeformat)
		ast_set_write_format(chan, writeformat);
	if (readformat)
		ast_set_read_format(chan, readformat);

	return res;
}
示例#3
0
static int measurenoise(struct ast_channel *chan, int ms, char *who)
{
	int res=0;
	int mssofar;
	int noise=0;
	int samples=0;
	int x;
	short *foo;
	struct timeval start, tv;
	struct ast_frame *f;
	int rformat;
	rformat = chan->readformat;
	if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
		ast_log(LOG_NOTICE, "Unable to set to linear mode!\n");
		return -1;
	}
	gettimeofday(&start, NULL);
	for(;;) {
		gettimeofday(&tv, NULL);
		mssofar = (tv.tv_sec - start.tv_sec) * 1000;
		mssofar += (tv.tv_usec - start.tv_usec) / 1000;
		if (mssofar > ms)
			break;
		res = ast_waitfor(chan, ms - mssofar);
		if (res < 1)
			break;
		f = ast_read(chan);
		if (!f) {
			res = -1;
			break;
		}
		if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
			foo = (short *)f->data;
			for (x=0;x<f->samples;x++) {
				noise += abs(foo[x]);
				samples++;
			}
		}
	}

	if (rformat) {
		if (ast_set_read_format(chan, rformat)) {
			ast_log(LOG_NOTICE, "Unable to restore original format!\n");
			return -1;
		}
	}
	if (res < 0)
		return res;
	if (!samples) {
		ast_log(LOG_NOTICE, "No samples were received from the other side!\n");
		return -1;
	}
	ast_log(LOG_DEBUG, "%s: Noise: %d, samples: %d, avg: %d\n", who, noise, samples, noise / samples);
	return (noise / samples);
}
static int intercom_exec(struct ast_channel *chan, void *data)
{
	int res = 0;
	struct localuser *u;
	struct ast_frame *f;
	int oreadformat;
	LOCAL_USER_ADD(u);
	/* Remember original read format */
	oreadformat = chan->readformat;
	/* Set mode to signed linear */
	res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
	if (res < 0) {
		ast_log(LOG_WARNING, "Unable to set format to signed linear on channel %s\n", chan->name);
		LOCAL_USER_REMOVE(u);
		return -1;
	}
	/* Read packets from the channel */
	while(!res) {
		res = ast_waitfor(chan, -1);
		if (res > 0) {
			res = 0;
			f = ast_read(chan);
			if (f) {
				if (f->frametype == AST_FRAME_DTMF) {
					ast_frfree(f);
					break;
				} else {
					if (f->frametype == AST_FRAME_VOICE) {
						if (f->subclass == AST_FORMAT_SLINEAR) {
							res = write_audio(f->data, f->datalen);
							if (res > 0)
								res = 0;
						} else
							ast_log(LOG_DEBUG, "Unable to handle non-signed linear frame (%d)\n", f->subclass);
					} 
				}
				ast_frfree(f);
			} else
				res = -1;
		}
	}
	
	if (!res)
		ast_set_read_format(chan, oreadformat);

	LOCAL_USER_REMOVE(u);

	return res;
}
示例#5
0
static int echo_exec(struct ast_channel *chan, void *data)
{
	int res = -1;
	int format;
	struct ast_module_user *u;

	u = ast_module_user_add(chan);

	format = ast_best_codec(chan->nativeformats);
	ast_set_write_format(chan, format);
	ast_set_read_format(chan, format);

	while (ast_waitfor(chan, -1) > -1) {
		struct ast_frame *f = ast_read(chan);
		if (!f)
			break;
		f->delivery.tv_sec = 0;
		f->delivery.tv_usec = 0;
		if (ast_write(chan, f)) {
			ast_frfree(f);
			goto end;
		}
		if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
			res = 0;
			ast_frfree(f);
			goto end;
		}
		ast_frfree(f);
	}
end:
	ast_module_user_remove(u);
	return res;
}
示例#6
0
static int echo_exec(struct ast_channel *chan, const char *data)
{
	int res = -1;
	struct ast_format format;

	ast_best_codec(chan->nativeformats, &format);
	ast_set_write_format(chan, &format);
	ast_set_read_format(chan, &format);

	while (ast_waitfor(chan, -1) > -1) {
		struct ast_frame *f = ast_read(chan);
		if (!f) {
			break;
		}
		f->delivery.tv_sec = 0;
		f->delivery.tv_usec = 0;
		if (ast_write(chan, f)) {
			ast_frfree(f);
			goto end;
		}
		if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) {
			res = 0;
			ast_frfree(f);
			goto end;
		}
		ast_frfree(f);
	}
end:
	return res;
}
示例#7
0
static int echo_exec(struct ast_channel *chan, void *data)
{
	int res = -1;
	int format;
	struct localuser *u;

	LOCAL_USER_ADD(u);

	format = ast_best_codec(chan->nativeformats);
	ast_set_write_format(chan, format);
	ast_set_read_format(chan, format);

	while (ast_waitfor(chan, -1) > -1) {
		struct ast_frame *f = ast_read(chan);
		if (!f)
			break;
		f->delivery.tv_sec = 0;
		f->delivery.tv_usec = 0;
		switch (f->frametype) {
		case AST_FRAME_DTMF:
		case AST_FRAME_DTMF_END:
			if (f->subclass == '#') {
				res = 0;
				ast_frfree(f);
				goto end;
			}
			/* fall through */
		case AST_FRAME_DTMF_BEGIN:
		case AST_FRAME_VOICE:
		case AST_FRAME_VIDEO:
		case AST_FRAME_TEXT:
		case AST_FRAME_HTML:
		case AST_FRAME_IMAGE:
			if (ast_write(chan, f)) {
				ast_frfree(f);
				goto end;
			}
		}
		ast_frfree(f);
	}
end:
	LOCAL_USER_REMOVE(u);
	return res;
}
示例#8
0
static int old_milliwatt_exec(struct ast_channel *chan)
{
	ast_set_write_format(chan, AST_FORMAT_ULAW);
	ast_set_read_format(chan, AST_FORMAT_ULAW);

	if (chan->_state != AST_STATE_UP) {
		ast_answer(chan);
	}

	if (ast_activate_generator(chan,&milliwattgen,"milliwatt") < 0) {
		ast_log(LOG_WARNING,"Failed to activate generator on '%s'\n",chan->name);
		return -1;
	}

	while (!ast_safe_sleep(chan, 10000))
		;

	ast_deactivate_generator(chan);

	return -1;
}
示例#9
0
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags)
{
	struct ast_conference *prev=NULL, *cur;
	struct ast_conf_user *user = malloc(sizeof(struct ast_conf_user));
	int fd;
	struct zt_confinfo ztc;
	struct ast_frame *f;
	struct ast_channel *c;
	struct ast_frame fr;
	int outfd;
	int ms;
	int nfds;
	int res;
	int flags;
	int retryzap;
	int origfd;
	int musiconhold = 0;
	int firstpass = 0;
	int origquiet;
	int ret = -1;
	int x;
	int menu_active = 0;
	int using_pseudo = 0;

	struct ast_app *app;
	char *agifile;
	char *agifiledefault = "conf-background.agi";
	char meetmesecs[30] = "";
	char exitcontext[AST_MAX_EXTENSION] = "";
	int dtmf;

	ZT_BUFFERINFO bi;
	char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
	char *buf = __buf + AST_FRIENDLY_OFFSET;
	
	if (!user) {
		ast_log(LOG_ERROR, "Out of memory\n");
		return(ret);
	}
	memset(user, 0, sizeof(struct ast_conf_user));

	user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */

	time(&user->jointime);

	if (conf->locked) {
		/* Sorry, but this confernce is locked! */	
		if (!ast_streamfile(chan, "conf-locked", chan->language))
			ast_waitstream(chan, "");
		goto outrun;
	}
	conf->users++;
	if (confflags & CONFFLAG_MARKEDUSER)
		conf->markedusers++;
      
   	ast_mutex_lock(&conflock);
	if (conf->firstuser == NULL) {
		/* Fill the first new User struct */
		user->user_no = 1;
		user->nextuser = NULL;
		user->prevuser = NULL;
		conf->firstuser = user;
		conf->lastuser = user;
	} else {
		/* Fill the new user struct */	
		user->user_no = conf->lastuser->user_no + 1; 
		user->prevuser = conf->lastuser;
		user->nextuser = NULL;
		if (conf->lastuser->nextuser != NULL) {
			ast_log(LOG_WARNING, "Error in User Management!\n");
			ast_mutex_unlock(&conflock);
			goto outrun;
		} else {
			conf->lastuser->nextuser = user;
			conf->lastuser = user;
		}
	}
	user->chan = chan;
	user->userflags = confflags;
	user->adminflags = 0;
	ast_mutex_unlock(&conflock);
	origquiet = confflags & CONFFLAG_QUIET;
	if (confflags & CONFFLAG_EXIT_CONTEXT) {
		if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) 
			strncpy(exitcontext, agifile, sizeof(exitcontext) - 1);
		else if (!ast_strlen_zero(chan->macrocontext)) 
			strncpy(exitcontext, chan->macrocontext, sizeof(exitcontext) - 1);
		else
			strncpy(exitcontext, chan->context, sizeof(exitcontext) - 1);
	}
	while((confflags & CONFFLAG_WAITMARKED) && (conf->markedusers == 0)) {
		confflags &= ~CONFFLAG_QUIET;
		confflags |= origquiet;
		/* XXX Announce that we're waiting on the conference lead to join */
		if (!(confflags & CONFFLAG_QUIET)) {
			res = ast_streamfile(chan, "vm-dialout", chan->language);
			if (!res)
				res = ast_waitstream(chan, "");
		} else
			res = 0;
		/* If we're waiting with hold music, set to silent mode */
		if (!res) {
			confflags |= CONFFLAG_QUIET;
			ast_moh_start(chan, NULL);
			res = ast_safe_sleep_conditional(chan, 60000, confnonzero, conf);
			ast_moh_stop(chan);
		}
		if (res < 0) {
			ast_log(LOG_DEBUG, "Got hangup on '%s' already\n", chan->name);
			goto outrun;
		}
	}
	
	if (!(confflags & CONFFLAG_QUIET) && conf->users == 1) {
		if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) {
			if (ast_waitstream(chan, "") < 0)
				goto outrun;
		} else
			goto outrun;
	}

	/* Set it into linear mode (write) */
	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
		ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
		goto outrun;
	}

	/* Set it into linear mode (read) */
	if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
		ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
		goto outrun;
	}
	ast_indicate(chan, -1);
	retryzap = strcasecmp(chan->type, "Zap");
zapretry:
	origfd = chan->fds[0];
	if (retryzap) {
		fd = open("/dev/zap/pseudo", O_RDWR);
		if (fd < 0) {
			ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
			goto outrun;
		}
		using_pseudo = 1;
		/* Make non-blocking */
		flags = fcntl(fd, F_GETFL);
		if (flags < 0) {
			ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
			ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		/* Setup buffering information */
		memset(&bi, 0, sizeof(bi));
		bi.bufsize = CONF_SIZE/2;
		bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
		bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
		bi.numbufs = 4;
		if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
			ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		x = 1;
		if (ioctl(fd, ZT_SETLINEAR, &x)) {
			ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		nfds = 1;
	} else {
		/* XXX Make sure we're not running on a pseudo channel XXX */
		fd = chan->fds[0];
		nfds = 0;
	}
	memset(&ztc, 0, sizeof(ztc));
	/* Check to see if we're in a conference... */
	ztc.chan = 0;	
	if (ioctl(fd, ZT_GETCONF, &ztc)) {
		ast_log(LOG_WARNING, "Error getting conference\n");
		close(fd);
		goto outrun;
	}
	if (ztc.confmode) {
		/* Whoa, already in a conference...  Retry... */
		if (!retryzap) {
			ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
			retryzap = 1;
			goto zapretry;
		}
	}
	memset(&ztc, 0, sizeof(ztc));
	/* Add us to the conference */
	ztc.chan = 0;	
	ztc.confno = conf->zapconf;
	if (confflags & CONFFLAG_MONITOR)
		ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
	else if (confflags & CONFFLAG_TALKER)
		ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
	else 
		ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;

	if (ioctl(fd, ZT_SETCONF, &ztc)) {
		ast_log(LOG_WARNING, "Error setting conference\n");
		close(fd);
		goto outrun;
	}
	ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf);

	manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
			"Channel: %s\r\n"
			"Uniqueid: %s\r\n"
			"Meetme: %s\r\n"
			"Usernum: %i\r\n",
			chan->name, chan->uniqueid, conf->confno, user->user_no);

	if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
		firstpass = 1;
		if (!(confflags & CONFFLAG_QUIET))
			conf_play(conf, ENTER);
	}

	if (confflags & CONFFLAG_AGI) {

		/* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
		  or use default filename of conf-background.agi */

		agifile = pbx_builtin_getvar_helper(chan,"MEETME_AGI_BACKGROUND");
		if (!agifile)
			agifile = agifiledefault;

		if (!strcasecmp(chan->type,"Zap")) {
			/*  Set CONFMUTE mode on Zap channel to mute DTMF tones */
			x = 1;
			ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
		}
		/* Find a pointer to the agi app and execute the script */
		app = pbx_findapp("agi");
		if (app) {
			ret = pbx_exec(chan, app, agifile, 1);
		} else {
			ast_log(LOG_WARNING, "Could not find application (agi)\n");
			ret = -2;
		}
		if (!strcasecmp(chan->type,"Zap")) {
			/*  Remove CONFMUTE mode on Zap channel */
			x = 0;
			ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
		}
	} else {
		if (!strcasecmp(chan->type,"Zap") && (confflags & CONFFLAG_STARMENU)) {
			/*  Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
			x = 1;
			ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
		}	
		for(;;) {
			outfd = -1;
			ms = -1;
			c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
			
			/* Update the struct with the actual confflags */
			user->userflags = confflags;
			
			/* trying to add moh for single person conf */
			if (confflags & CONFFLAG_MOH) {
				if (conf->users == 1) {
					if (musiconhold == 0) {
						ast_moh_start(chan, NULL);
						musiconhold = 1;
					} 
				} else {
					if (musiconhold) {
						ast_moh_stop(chan);
						musiconhold = 0;
					}
				}
			}
			
			/* Leave if the last marked user left */
			if (conf->markedusers == 0 && confflags & CONFFLAG_MARKEDEXIT) {
				ret = -1;
				break;
			}
	
			/* Check if the admin changed my modes */
			if (user->adminflags) {			
				/* Set the new modes */
				if ((user->adminflags & ADMINFLAG_MUTED) && (ztc.confmode & ZT_CONF_TALKER)) {
					ztc.confmode ^= ZT_CONF_TALKER;
					if (ioctl(fd, ZT_SETCONF, &ztc)) {
						ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
						ret = -1;
						break;
					}
				}
				if (!(user->adminflags & ADMINFLAG_MUTED) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
					ztc.confmode |= ZT_CONF_TALKER;
					if (ioctl(fd, ZT_SETCONF, &ztc)) {
						ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
						ret = -1;
						break;
					}
				}
				if (user->adminflags & ADMINFLAG_KICKME) {
					//You have been kicked.
					if (!ast_streamfile(chan, "conf-kicked", chan->language))
						ast_waitstream(chan, "");
					ret = 0;
					break;
				}
			} else if (!(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
				ztc.confmode |= ZT_CONF_TALKER;
				if (ioctl(fd, ZT_SETCONF, &ztc)) {
					ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
					ret = -1;
					break;
				}
			}

			if (c) {
				if (c->fds[0] != origfd) {
					if (using_pseudo) {
						/* Kill old pseudo */
						close(fd);
					}
					ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
					retryzap = 0;
					using_pseudo = 0;
					goto zapretry;
				}
				f = ast_read(c);
				if (!f) 
					break;
				if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
					char tmp[2];
					tmp[0] = f->subclass;
					tmp[1] = '\0';
					if (ast_exists_extension(chan, exitcontext, tmp, 1, chan->callerid)) {
						strncpy(chan->context, exitcontext, sizeof(chan->context) - 1);
						strncpy(chan->exten, tmp, sizeof(chan->exten) - 1);
						chan->priority = 0;
						ret = 0;
						break;
					}
				} else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
					ret = 0;
					break;
				} else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
					if (musiconhold) {
			   			ast_moh_stop(chan);
					}
					if ((confflags & CONFFLAG_ADMIN)) {
						/* Admin menu */
						if (!menu_active) {
							menu_active = 1;
							/* Record this sound! */
							if (!ast_streamfile(chan, "conf-adminmenu", chan->language))
								dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
							else
								dtmf = 0;
						} else 
							dtmf = f->subclass;
						if (dtmf) {
							switch(dtmf) {
								case '1': /* Un/Mute */
									menu_active = 0;
		 							if (ztc.confmode & ZT_CONF_TALKER) {
	 						       		ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
	 						       		confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
									} else {
										ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
										confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
									}
									if (ioctl(fd, ZT_SETCONF, &ztc)) {
										ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
										ret = -1;
										break;
									}
									if (ztc.confmode & ZT_CONF_TALKER) {
										if (!ast_streamfile(chan, "conf-unmuted", chan->language))
											ast_waitstream(chan, "");
									} else {
										if (!ast_streamfile(chan, "conf-muted", chan->language))
											ast_waitstream(chan, "");
									}
									break;
								case '2': /* Un/Lock the Conference */
									menu_active = 0;
									if (conf->locked) {
										conf->locked = 0;
										if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
											ast_waitstream(chan, "");
									} else {
										conf->locked = 1;
										if (!ast_streamfile(chan, "conf-lockednow", chan->language))
											ast_waitstream(chan, "");
									}
									break;
								default:
									menu_active = 0;
									/* Play an error message! */
									if (!ast_streamfile(chan, "conf-errormenu", chan->language))
										ast_waitstream(chan, "");
									break;
							}
						}
					} else {
						/* User menu */
						if (!menu_active) {
							menu_active = 1;
							/* Record this sound! */
							if (!ast_streamfile(chan, "conf-usermenu", chan->language))
								dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
							else
								dtmf = 0;
						} else 
							dtmf = f->subclass;
						if (dtmf) {
							switch(dtmf) {
								case '1': /* Un/Mute */
									menu_active = 0;
		 							if (ztc.confmode & ZT_CONF_TALKER) {
	 						       		ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
	 						       		confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
									} else if (!(user->adminflags & ADMINFLAG_MUTED)) {
										ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
										confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
									}
									if (ioctl(fd, ZT_SETCONF, &ztc)) {
										ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
										ret = -1;
										break;
									}
									if (ztc.confmode & ZT_CONF_TALKER) {
										if (!ast_streamfile(chan, "conf-unmuted", chan->language))
											ast_waitstream(chan, "");
									} else {
										if (!ast_streamfile(chan, "conf-muted", chan->language))
											ast_waitstream(chan, "");
									}
									break;
								default:
									menu_active = 0;
									/* Play an error message! */
									if (!ast_streamfile(chan, "conf-errormenu", chan->language))
										ast_waitstream(chan, "");
									break;
							}
						}
					}
					if (musiconhold) {
			   			ast_moh_start(chan, NULL);
					}
				} else if (using_pseudo) {
					if (f->frametype == AST_FRAME_VOICE) {
						if (f->subclass == AST_FORMAT_SLINEAR) {
							/* Carefully write */
							careful_write(fd, f->data, f->datalen);
						} else
							ast_log(LOG_WARNING, "Huh?  Got a non-linear (%d) frame in the conference\n", f->subclass);
					}
				}
				ast_frfree(f);
			} else if (outfd > -1) {
				res = read(outfd, buf, CONF_SIZE);
				if (res > 0) {
					memset(&fr, 0, sizeof(fr));
					fr.frametype = AST_FRAME_VOICE;
					fr.subclass = AST_FORMAT_SLINEAR;
					fr.datalen = res;
					fr.samples = res/2;
					fr.data = buf;
					fr.offset = AST_FRIENDLY_OFFSET;
					if (ast_write(chan, &fr) < 0) {
						ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
						/* break; */
					}
				} else 
					ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
			}
		}
	}
	if (using_pseudo)
		close(fd);
	else {
		/* Take out of conference */
		/* Add us to the conference */
		ztc.chan = 0;	
		ztc.confno = 0;
		ztc.confmode = 0;
		if (ioctl(fd, ZT_SETCONF, &ztc)) {
			ast_log(LOG_WARNING, "Error setting conference\n");
		}
	}
	if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
		conf_play(conf, LEAVE);

outrun:
	ast_mutex_lock(&conflock);
	if (user->user_no) { /* Only cleanup users who really joined! */
		manager_event(EVENT_FLAG_CALL, "MeetmeLeave", 
			"Channel: %s\r\n"
			"Uniqueid: %s\r\n"
			"Meetme: %s\r\n"
			"Usernum: %i\r\n",
			chan->name, chan->uniqueid, conf->confno, user->user_no);
		prev = NULL;
		conf->users--;
		if (confflags & CONFFLAG_MARKEDUSER) 
			conf->markedusers--;
		cur = confs;
		if (!conf->users) {
			/* No more users -- close this one out */
			while(cur) {
				if (cur == conf) {
					if (prev)
						prev->next = conf->next;
					else
						confs = conf->next;
					break;
				}
				prev = cur;
				cur = cur->next;
			}
			if (!cur) 
				ast_log(LOG_WARNING, "Conference not found\n");
			if (conf->chan)
				ast_hangup(conf->chan);
			else
				close(conf->fd);
			free(conf);
		} else {
			/* Remove the user struct */ 
			if (user == conf->firstuser) {
				if (user->nextuser) {
					/* There is another entry */
					user->nextuser->prevuser = NULL;
				} else {
					/* We are the only entry */
					conf->lastuser = NULL;
				}
				/* In either case */
				conf->firstuser = user->nextuser;
			} else if (user == conf->lastuser){
				if (user->prevuser)
					user->prevuser->nextuser = NULL;
				else
					ast_log(LOG_ERROR, "Bad bad bad!  We're the last, not the first, but nobody before us??\n");
				conf->lastuser = user->prevuser;
			} else {
				if (user->nextuser)
					user->nextuser->prevuser = user->prevuser;
				else
					ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n");
				if (user->prevuser)
					user->prevuser->nextuser = user->nextuser;
				else
					ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n");
			}
		}
		/* Return the number of seconds the user was in the conf */
		snprintf(meetmesecs, sizeof(meetmesecs), "%i", (int) (time(NULL) - user->jointime));
		pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
	}
	free(user);
	ast_mutex_unlock(&conflock);
	return ret;
}
示例#10
0
/*! \brief SpeechBackground(Sound File|Timeout) Dialplan Application */
static int speech_background(struct ast_channel *chan, void *data)
{
        unsigned int timeout = 0;
        int res = 0, done = 0, argc = 0, started = 0, quieted = 0, max_dtmf_len = 0;
        struct ast_module_user *u = NULL;
        struct ast_speech *speech = find_speech(chan);
        struct ast_frame *f = NULL;
        int oldreadformat = AST_FORMAT_SLINEAR;
        char dtmf[AST_MAX_EXTENSION] = "";
        time_t start, current;
        struct ast_datastore *datastore = NULL;
        char *argv[2], *args = NULL, *filename_tmp = NULL, *filename = NULL, tmp[2] = "", dtmf_terminator = '#';
	const char *tmp2 = NULL;

        args = ast_strdupa(data);

        u = ast_module_user_add(chan);

        if (speech == NULL) {
                ast_module_user_remove(u);
                return -1;
        }

	/* If channel is not already answered, then answer it */
	if (chan->_state != AST_STATE_UP && ast_answer(chan)) {
		ast_module_user_remove(u);
		return -1;
	}

        /* Record old read format */
        oldreadformat = chan->readformat;

        /* Change read format to be signed linear */
        if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
                ast_module_user_remove(u);
                return -1;
        }

        /* Parse out options */
        argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0]));
        if (argc > 0) {
                /* Yay sound file */
                filename_tmp = ast_strdupa(argv[0]);
		if (!ast_strlen_zero(argv[1])) {
			if ((timeout = atoi(argv[1])) == 0)
				timeout = -1;
		} else
			timeout = 0;
        }

	/* See if the maximum DTMF length variable is set... we use a variable in case they want to carry it through their entire dialplan */
	if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_MAXLEN")) && !ast_strlen_zero(tmp2))
		max_dtmf_len = atoi(tmp2);

	/* See if a terminator is specified */
	if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_TERMINATOR"))) {
		if (ast_strlen_zero(tmp2))
			dtmf_terminator = '\0';
		else
			dtmf_terminator = tmp2[0];
	}

        /* Before we go into waiting for stuff... make sure the structure is ready, if not - start it again */
        if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
		ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
                ast_speech_start(speech);
        }

	/* Ensure no streams are currently running */
	ast_stopstream(chan);

        /* Okay it's streaming so go into a loop grabbing frames! */
        while (done == 0) {
		/* If the filename is null and stream is not running, start up a new sound file */
		if (!quieted && (chan->streamid == -1 && chan->timingfunc == NULL) && (filename = strsep(&filename_tmp, "&"))) {
			/* Discard old stream information */
			ast_stopstream(chan);
			/* Start new stream */
			speech_streamfile(chan, filename, chan->language);
		}

                /* Run scheduled stuff */
                ast_sched_runq(chan->sched);

                /* Yay scheduling */
                res = ast_sched_wait(chan->sched);
                if (res < 0) {
                        res = 1000;
                }

                /* If there is a frame waiting, get it - if not - oh well */
                if (ast_waitfor(chan, res) > 0) {
                        f = ast_read(chan);
                        if (f == NULL) {
                                /* The channel has hung up most likely */
                                done = 3;
                                break;
                        }
                }

		/* Do timeout check (shared between audio/dtmf) */
		if ((!quieted || strlen(dtmf)) && started == 1) {
			time(&current);
			if ((current-start) >= timeout) {
				done = 1;
				if (f)
					ast_frfree(f);
				break;
			}
		}

                /* Do checks on speech structure to see if it's changed */
                ast_mutex_lock(&speech->lock);
                if (ast_test_flag(speech, AST_SPEECH_QUIET)) {
			if (chan->stream)
				ast_stopstream(chan);
			ast_clear_flag(speech, AST_SPEECH_QUIET);
			quieted = 1;
                }
                /* Check state so we can see what to do */
                switch (speech->state) {
                case AST_SPEECH_STATE_READY:
                        /* If audio playback has stopped do a check for timeout purposes */
                        if (chan->streamid == -1 && chan->timingfunc == NULL)
                                ast_stopstream(chan);
                        if (!quieted && chan->stream == NULL && timeout && started == 0 && !filename_tmp) {
				if (timeout == -1) {
					done = 1;
					if (f)
						ast_frfree(f);
					break;
				}
				time(&start);
				started = 1;
                        }
                        /* Write audio frame out to speech engine if no DTMF has been received */
                        if (!strlen(dtmf) && f != NULL && f->frametype == AST_FRAME_VOICE) {
                                ast_speech_write(speech, f->data, f->datalen);
                        }
                        break;
                case AST_SPEECH_STATE_WAIT:
                        /* Cue up waiting sound if not already playing */
			if (!strlen(dtmf)) {
				if (chan->stream == NULL) {
					if (speech->processing_sound != NULL) {
						if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
							speech_streamfile(chan, speech->processing_sound, chan->language);
						}
					}
				} else if (chan->streamid == -1 && chan->timingfunc == NULL) {
					ast_stopstream(chan);
					if (speech->processing_sound != NULL) {
						if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
							speech_streamfile(chan, speech->processing_sound, chan->language);
						}
					}
				}
			}
                        break;
                case AST_SPEECH_STATE_DONE:
			/* Now that we are done... let's switch back to not ready state */
			ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
			if (!strlen(dtmf)) {
				/* Copy to speech structure the results, if available */
				speech->results = ast_speech_results_get(speech);
				/* Break out of our background too */
				done = 1;
				/* Stop audio playback */
				if (chan->stream != NULL) {
					ast_stopstream(chan);
				}
			}
                        break;
                default:
                        break;
                }
                ast_mutex_unlock(&speech->lock);

                /* Deal with other frame types */
                if (f != NULL) {
                        /* Free the frame we received */
                        switch (f->frametype) {
                        case AST_FRAME_DTMF:
				if (dtmf_terminator != '\0' && f->subclass == dtmf_terminator) {
					done = 1;
				} else {
					if (chan->stream != NULL) {
						ast_stopstream(chan);
					}
					if (!started) {
						/* Change timeout to be 5 seconds for DTMF input */
						timeout = (chan->pbx && chan->pbx->dtimeout) ? chan->pbx->dtimeout : 5;
						started = 1;
					}
					time(&start);
					snprintf(tmp, sizeof(tmp), "%c", f->subclass);
					strncat(dtmf, tmp, sizeof(dtmf) - strlen(dtmf) - 1);
					/* If the maximum length of the DTMF has been reached, stop now */
					if (max_dtmf_len && strlen(dtmf) == max_dtmf_len)
						done = 1;
				}
                                break;
                        case AST_FRAME_CONTROL:
                                switch (f->subclass) {
                                case AST_CONTROL_HANGUP:
                                        /* Since they hung up we should destroy the speech structure */
                                        done = 3;
                                default:
                                        break;
                                }
                        default:
                                break;
                        }
                        ast_frfree(f);
                        f = NULL;
                }
        }

	if (strlen(dtmf)) {
		/* We sort of make a results entry */
		speech->results = ast_calloc(1, sizeof(*speech->results));
		if (speech->results != NULL) {
			ast_speech_dtmf(speech, dtmf);
			speech->results->score = 1000;
			speech->results->text = strdup(dtmf);
			speech->results->grammar = strdup("dtmf");
		}
		ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
	}

        /* See if it was because they hung up */
        if (done == 3) {
                /* Destroy speech structure */
                ast_speech_destroy(speech);
                datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
                if (datastore != NULL) {
                        ast_channel_datastore_remove(chan, datastore);
                }
        } else {
                /* Channel is okay so restore read format */
                ast_set_read_format(chan, oldreadformat);
        }

        ast_module_user_remove(u);

        return 0;
}
示例#11
0
int AST_OPTIONAL_API_NAME(ast_adsi_transmit_message_full)(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait)
{
	unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL };
	int msglens[5], msgtypes[5], newdatamode = (ast_channel_adsicpe(chan) & ADSI_FLAG_DATAMODE), res, x, waitforswitch = 0;
	struct ast_format writeformat;
	struct ast_format readformat;

	ast_format_copy(&writeformat, ast_channel_writeformat(chan));
	ast_format_copy(&readformat, ast_channel_readformat(chan));

	for (x = 0; x < msglen; x += (msg[x+1]+2)) {
		if (msg[x] == ADSI_SWITCH_TO_DATA) {
			ast_debug(1, "Switch to data is sent!\n");
			waitforswitch++;
			newdatamode = ADSI_FLAG_DATAMODE;
		}

		if (msg[x] == ADSI_SWITCH_TO_VOICE) {
			ast_debug(1, "Switch to voice is sent!\n");
			waitforswitch++;
			newdatamode = 0;
		}
	}
	msgs[0] = msg;

	msglens[0] = msglen;
	msgtypes[0] = msgtype;

	if (msglen > 253) {
		ast_log(LOG_WARNING, "Can't send ADSI message of %d bytes, too large\n", msglen);
		return -1;
	}

	ast_stopstream(chan);

	if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW)) {
		ast_log(LOG_WARNING, "Unable to set write format to ULAW\n");
		return -1;
	}

	if (ast_set_read_format_by_id(chan, AST_FORMAT_ULAW)) {
		ast_log(LOG_WARNING, "Unable to set read format to ULAW\n");
		if (writeformat.id) {
			if (ast_set_write_format(chan, &writeformat)) {
				ast_log(LOG_WARNING, "Unable to restore write format to %s\n", ast_getformatname(&writeformat));
			}
		}
		return -1;
	}
	res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes);

	if (dowait) {
		ast_debug(1, "Wait for switch is '%d'\n", waitforswitch);
		while (waitforswitch-- && ((res = ast_waitfordigit(chan, 1000)) > 0)) {
			res = 0;
			ast_debug(1, "Waiting for 'B'...\n");
		}
	}

	if (!res) {
		ast_channel_adsicpe_set(chan, (ast_channel_adsicpe(chan) & ~ADSI_FLAG_DATAMODE) | newdatamode);
	}

	if (writeformat.id) {
		ast_set_write_format(chan, &writeformat);
	}
	if (readformat.id) {
		ast_set_read_format(chan, &readformat);
	}

	if (!res) {
		res = ast_safe_sleep(chan, 100 );
	}
	return res;
}
示例#12
0
static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
		    const struct pjmedia_sdp_media *stream)
{
	RAII_VAR(struct ast_format_cap *, caps, NULL, ast_format_cap_destroy);
	RAII_VAR(struct ast_format_cap *, peer, NULL, ast_format_cap_destroy);
	RAII_VAR(struct ast_format_cap *, joint, NULL, ast_format_cap_destroy);
	enum ast_format_type media_type = stream_to_media_type(session_media->stream_type);
	struct ast_rtp_codecs codecs;
	struct ast_format fmt;
	int fmts = 0;
	int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
		!ast_format_cap_is_empty(session->direct_media_cap);

	if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK)) ||
	    !(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK))) {
		ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type);
		return -1;
	}

	/* get the endpoint capabilities */
	if (direct_media_enabled) {
		ast_format_cap_joint_copy(session->endpoint->media.codecs, session->direct_media_cap, caps);
	} else {
		ast_format_cap_copy(caps, session->endpoint->media.codecs);
	}
	format_cap_only_type(caps, media_type);

	/* get the capabilities on the peer */
	get_codecs(session, stream, &codecs);
	ast_rtp_codecs_payload_formats(&codecs, peer, &fmts);

	/* get the joint capabilities between peer and endpoint */
	if (!(joint = ast_format_cap_joint(caps, peer))) {
		char usbuf[64], thembuf[64];

		ast_rtp_codecs_payloads_destroy(&codecs);

		ast_getformatname_multiple(usbuf, sizeof(usbuf), caps);
		ast_getformatname_multiple(thembuf, sizeof(thembuf), peer);
		ast_log(LOG_WARNING, "No joint capabilities between our configuration(%s) and incoming SDP(%s)\n", usbuf, thembuf);
		return -1;
	}

	ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp),
				     session_media->rtp);

	ast_format_cap_copy(caps, session->req_caps);
	ast_format_cap_remove_bytype(caps, media_type);
	ast_format_cap_append(caps, joint);
	ast_format_cap_append(session->req_caps, caps);

	if (session->channel) {
		ast_format_cap_copy(caps, ast_channel_nativeformats(session->channel));
		ast_format_cap_remove_bytype(caps, media_type);
		ast_codec_choose(&session->endpoint->media.prefs, joint, 1, &fmt);
		ast_format_cap_add(caps, &fmt);

		/* Apply the new formats to the channel, potentially changing read/write formats while doing so */
		ast_format_cap_copy(ast_channel_nativeformats(session->channel), caps);
		ast_set_read_format(session->channel, ast_channel_readformat(session->channel));
		ast_set_write_format(session->channel, ast_channel_writeformat(session->channel));
	}

	ast_rtp_codecs_payloads_destroy(&codecs);
	return 0;
}
示例#13
0
static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
		    const struct pjmedia_sdp_media *stream)
{
	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, peer, NULL, ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, joint, NULL, ao2_cleanup);
	enum ast_media_type media_type = stream_to_media_type(session_media->stream_type);
	struct ast_rtp_codecs codecs = AST_RTP_CODECS_NULL_INIT;
	int fmts = 0;
	int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
		ast_format_cap_count(session->direct_media_cap);
	int dsp_features = 0;

	if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
	    !(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
	    !(joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
		ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type);
		return -1;
	}

	/* get the endpoint capabilities */
	if (direct_media_enabled) {
		ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps);
		format_cap_only_type(caps, media_type);
	} else {
		ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type);
	}

	/* get the capabilities on the peer */
	get_codecs(session, stream, &codecs,  session_media);
	ast_rtp_codecs_payload_formats(&codecs, peer, &fmts);

	/* get the joint capabilities between peer and endpoint */
	ast_format_cap_get_compatible(caps, peer, joint);
	if (!ast_format_cap_count(joint)) {
		struct ast_str *usbuf = ast_str_alloca(256);
		struct ast_str *thembuf = ast_str_alloca(256);

		ast_rtp_codecs_payloads_destroy(&codecs);
		ast_log(LOG_NOTICE, "No joint capabilities for '%s' media stream between our configuration(%s) and incoming SDP(%s)\n",
			session_media->stream_type,
			ast_format_cap_get_names(caps, &usbuf),
			ast_format_cap_get_names(peer, &thembuf));
		return -1;
	}

	ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp),
				     session_media->rtp);

	ast_format_cap_append_from_cap(session->req_caps, joint, AST_MEDIA_TYPE_UNKNOWN);

	if (session->channel) {
		ast_channel_lock(session->channel);
		ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN);
		ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel),
			AST_MEDIA_TYPE_UNKNOWN);
		ast_format_cap_remove_by_type(caps, media_type);
		ast_format_cap_append_from_cap(caps, joint, media_type);

		/*
		 * Apply the new formats to the channel, potentially changing
		 * raw read/write formats and translation path while doing so.
		 */
		ast_channel_nativeformats_set(session->channel, caps);
		if (media_type == AST_MEDIA_TYPE_AUDIO) {
			ast_set_read_format(session->channel, ast_channel_readformat(session->channel));
			ast_set_write_format(session->channel, ast_channel_writeformat(session->channel));
		}
		if ((session->endpoint->dtmf == AST_SIP_DTMF_AUTO)
		    && (ast_rtp_instance_dtmf_mode_get(session_media->rtp) == AST_RTP_DTMF_MODE_RFC2833)
		    && (session->dsp)) {
			dsp_features = ast_dsp_get_features(session->dsp);
			dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
			if (dsp_features) {
				ast_dsp_set_features(session->dsp, dsp_features);
			} else {
				ast_dsp_free(session->dsp);
				session->dsp = NULL;
			}
		}
		ast_channel_unlock(session->channel);
	}

	ast_rtp_codecs_payloads_destroy(&codecs);
	return 0;
}
示例#14
0
static int transmit_audio(fax_session *s)
{
	int res = -1;
	struct ast_format original_read_fmt;
	struct ast_format original_write_fmt;
	fax_state_t fax;
	t30_state_t *t30state;
	struct ast_frame *inf = NULL;
	int last_state = 0;
	struct timeval now, start, state_change;
	enum ast_t38_state t38_state;
	struct ast_control_t38_parameters t38_parameters = { .version = 0,
							     .max_ifp = 800,
							     .rate = AST_T38_RATE_14400,
							     .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
							     .fill_bit_removal = 1,
/*
 * spandsp has API calls to support MMR and JBIG transcoding, but they aren't
 * implemented quite yet... so don't offer them to the remote endpoint
 *							     .transcoding_mmr = 1,
 *							     .transcoding_jbig = 1,
*/
	};

	ast_format_clear(&original_read_fmt);
	ast_format_clear(&original_write_fmt);

	/* if in called party mode, try to use T.38 */
	if (s->caller_mode == FALSE) {
		/* check if we are already in T.38 mode (unlikely), or if we can request
		 * a switch... if so, request it now and wait for the result, rather
		 * than starting an audio FAX session that will have to be cancelled
		 */
		if ((t38_state = ast_channel_get_t38_state(s->chan)) == T38_STATE_NEGOTIATED) {
			return 1;
		} else if ((t38_state != T38_STATE_UNAVAILABLE) &&
			   (t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE,
			    (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0))) {
			/* wait up to five seconds for negotiation to complete */
			unsigned int timeout = 5000;
			int ms;

			ast_debug(1, "Negotiating T.38 for receive on %s\n", ast_channel_name(s->chan));
			while (timeout > 0) {
				ms = ast_waitfor(s->chan, 1000);
				if (ms < 0) {
					ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan));
					return -1;
				}
				if (!ms) {
					/* nothing happened */
					if (timeout > 0) {
						timeout -= 1000;
						continue;
					} else {
						ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", ast_channel_name(s->chan));
						break;
					}
				}
				if (!(inf = ast_read(s->chan))) {
					return -1;
				}
				if ((inf->frametype == AST_FRAME_CONTROL) &&
				    (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
				    (inf->datalen == sizeof(t38_parameters))) {
					struct ast_control_t38_parameters *parameters = inf->data.ptr;

					switch (parameters->request_response) {
					case AST_T38_NEGOTIATED:
						ast_debug(1, "Negotiated T.38 for receive on %s\n", ast_channel_name(s->chan));
						res = 1;
						break;
					case AST_T38_REFUSED:
						ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", ast_channel_name(s->chan));
						break;
					default:
						ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", ast_channel_name(s->chan));
						break;
					}
					ast_frfree(inf);
					if (res == 1) {
						return 1;
					} else {
						break;
					}
				}
				ast_frfree(inf);
			}
		}
	}

#if SPANDSP_RELEASE_DATE >= 20080725
        /* for spandsp shaphots 0.0.6 and higher */
        t30state = &fax.t30;
#else
        /* for spandsp release 0.0.5 */
        t30state = &fax.t30_state;
#endif

	ast_format_copy(&original_read_fmt, ast_channel_readformat(s->chan));
	if (original_read_fmt.id != AST_FORMAT_SLINEAR) {
		res = ast_set_read_format_by_id(s->chan, AST_FORMAT_SLINEAR);
		if (res < 0) {
			ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
			goto done;
		}
	}

	ast_format_copy(&original_write_fmt, ast_channel_writeformat(s->chan));
	if (original_write_fmt.id != AST_FORMAT_SLINEAR) {
		res = ast_set_write_format_by_id(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(&t30state->logging);

	/* Configure terminal */
	set_local_info(t30state, s);
	set_file(t30state, s);
	set_ecm(t30state, TRUE);

	fax_set_transmit_on_idle(&fax, TRUE);

	t30_set_phase_e_handler(t30state, phase_e_handler, s);

	start = state_change = ast_tvnow();

	ast_activate_generator(s->chan, &generator, &fax);

	while (!s->finished) {
		inf = NULL;

		if ((res = ast_waitfor(s->chan, 25)) < 0) {
			ast_debug(1, "Error waiting for a frame\n");
			break;
		}

		/* 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;
		}

		if (!res) {
			/* There was timeout waiting for a frame. Loop around and wait again */
			continue;
		}

		/* There is a frame available. Get it */
		res = 0;

		if (!(inf = ast_read(s->chan))) {
			ast_debug(1, "Channel hangup\n");
			res = -1;
			break;
		}

		ast_debug(10, "frame %d/%u, len=%d\n", inf->frametype, (unsigned int) inf->subclass.format.id, inf->datalen);

		/* 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 channel format
		   to slinear so it will still be received by ast_read */
		if (inf->frametype == AST_FRAME_VOICE && inf->subclass.format.id == AST_FORMAT_SLINEAR) {
			if (fax_rx(&fax, inf->data.ptr, 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;
			}
			if (last_state != t30state->state) {
				state_change = ast_tvnow();
				last_state = t30state->state;
			}
		} else if ((inf->frametype == AST_FRAME_CONTROL) &&
			   (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS)) {
			struct ast_control_t38_parameters *parameters = inf->data.ptr;

			if (parameters->request_response == AST_T38_NEGOTIATED) {
				/* T38 switchover completed */
				s->t38parameters = *parameters;
				ast_debug(1, "T38 negotiated, finishing audio loop\n");
				res = 1;
				break;
			} else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) {
				t38_parameters.request_response = AST_T38_NEGOTIATED;
				ast_debug(1, "T38 request received, accepting\n");
				/* Complete T38 switchover */
				ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
				/* Do not break audio loop, wait until channel driver finally acks switchover
				 * with AST_T38_NEGOTIATED
				 */
			}
		}

		ast_frfree(inf);
		inf = NULL;
	}

	ast_debug(1, "Loop finished, res=%d\n", res);

	if (inf)
		ast_frfree(inf);

	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(t30state, NULL, NULL);
	}

	t30_terminate(t30state);
	fax_release(&fax);

done:
	if (original_write_fmt.id != 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", ast_channel_name(s->chan));
	}

	if (original_read_fmt.id != 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", ast_channel_name(s->chan));
	}

	return res;

}

static int transmit_t38(fax_session *s)
{
	int res = 0;
	t38_terminal_state_t t38;
	struct ast_frame *inf = NULL;
	int last_state = 0;
	struct timeval now, start, state_change, last_frame;
	t30_state_t *t30state;
	t38_core_state_t *t38state;

#if SPANDSP_RELEASE_DATE >= 20080725
	/* for spandsp shaphots 0.0.6 and higher */
	t30state = &t38.t30;
	t38state = &t38.t38_fe.t38;
#else
	/* for spandsp releases 0.0.5 */
	t30state = &t38.t30_state;
	t38state = &t38.t38;
#endif

	/* Initialize terminal */
	memset(&t38, 0, sizeof(t38));
	if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
		ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
		res = -1;
		goto disable_t38;
	}

	t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp);

	if (s->t38parameters.fill_bit_removal) {
		t38_set_fill_bit_removal(t38state, TRUE);
	}
	if (s->t38parameters.transcoding_mmr) {
		t38_set_mmr_transcoding(t38state, TRUE);
	}
	if (s->t38parameters.transcoding_jbig) {
		t38_set_jbig_transcoding(t38state, TRUE);
	}

	/* Setup logging */
	set_logging(&t38.logging);
	set_logging(&t30state->logging);
	set_logging(&t38state->logging);

	/* Configure terminal */
	set_local_info(t30state, s);
	set_file(t30state, s);
	set_ecm(t30state, TRUE);

	t30_set_phase_e_handler(t30state, phase_e_handler, s);

	now = start = state_change = ast_tvnow();

	while (!s->finished) {
		inf = NULL;

		if ((res = ast_waitfor(s->chan, 25)) < 0) {
			ast_debug(1, "Error waiting for a frame\n");
			break;
		}

		last_frame = now;

		/* 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;
		}

		t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));

		if (!res) {
			/* There was timeout waiting for a frame. Loop around and wait again */
			continue;
		}

		/* There is a frame available. Get it */
		res = 0;

		if (!(inf = ast_read(s->chan))) {
			ast_debug(1, "Channel hangup\n");
			res = -1;
			break;
		}

		ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass.integer, inf->datalen);

		if (inf->frametype == AST_FRAME_MODEM && inf->subclass.integer == AST_MODEM_T38) {
			t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno);
			if (last_state != t30state->state) {
				state_change = ast_tvnow();
				last_state = t30state->state;
			}
		} else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
			struct ast_control_t38_parameters *parameters = inf->data.ptr;
			if (parameters->request_response == AST_T38_TERMINATED) {
				ast_debug(1, "T38 down, finishing\n");
				break;
			}
		}

		ast_frfree(inf);
		inf = NULL;
	}

	ast_debug(1, "Loop finished, res=%d\n", res);

	if (inf)
		ast_frfree(inf);

	t30_terminate(t30state);
	t38_terminal_release(&t38);

disable_t38:
	/* if we are not the caller, it's our job to shut down the T.38
	 * session when the FAX transmisson is complete.
	 */
	if ((s->caller_mode == FALSE) &&
	    (ast_channel_get_t38_state(s->chan) == T38_STATE_NEGOTIATED)) {
		struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };

		if (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) {
			/* wait up to five seconds for negotiation to complete */
			unsigned int timeout = 5000;
			int ms;

			ast_debug(1, "Shutting down T.38 on %s\n", ast_channel_name(s->chan));
			while (timeout > 0) {
				ms = ast_waitfor(s->chan, 1000);
				if (ms < 0) {
					ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan));
					return -1;
				}
				if (!ms) {
					/* nothing happened */
					if (timeout > 0) {
						timeout -= 1000;
						continue;
					} else {
						ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", ast_channel_name(s->chan));
						break;
					}
				}
				if (!(inf = ast_read(s->chan))) {
					return -1;
				}
				if ((inf->frametype == AST_FRAME_CONTROL) &&
				    (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
				    (inf->datalen == sizeof(t38_parameters))) {
					struct ast_control_t38_parameters *parameters = inf->data.ptr;

					switch (parameters->request_response) {
					case AST_T38_TERMINATED:
						ast_debug(1, "Shut down T.38 on %s\n", ast_channel_name(s->chan));
						break;
					case AST_T38_REFUSED:
						ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", ast_channel_name(s->chan));
						break;
					default:
						ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", ast_channel_name(s->chan));
						break;
					}
					ast_frfree(inf);
					break;
				}
				ast_frfree(inf);
			}
		}
	}

	return res;
}
示例#15
0
/*!
 * \brief This is the main function called by Asterisk Core whenever the App is invoked in the extension logic.
 *
 * \param chan Asterisk Channel
 * \param data Application data
 *
 * \retval 0 success
 * \retval -1 failure
 */
static int alarmreceiver_exec(struct ast_channel *chan, const char *data)
{
	int res = 0;
	int no_checksum = 0;
	event_node_t *elp, *efree;
	char signalling_type[64] = "";
	event_node_t *event_head = NULL;

	if ((ast_format_cmp(ast_channel_writeformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) &&
		(ast_format_cmp(ast_channel_writeformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) {
		ast_verb(4, "AlarmReceiver: Setting write format to Mu-law\n");
		if (ast_set_write_format(chan, ast_format_ulaw)) {
			ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan));
			return -1;
		}
	}

	if ((ast_format_cmp(ast_channel_readformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) &&
		(ast_format_cmp(ast_channel_readformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) {
		ast_verb(4, "AlarmReceiver: Setting read format to Mu-law\n");
		if (ast_set_read_format(chan, ast_format_ulaw)) {
			ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan));
			return -1;
		}
	}

	/* Set default values for this invocation of the application */
	ast_copy_string(signalling_type, UNKNOWN_FORMAT, sizeof(signalling_type));
	call_start_time = ast_tvnow();

	/* Answer the channel if it is not already */
	if (ast_channel_state(chan) != AST_STATE_UP) {
		ast_verb(4, "AlarmReceiver: Answering channel\n");
		if (ast_answer(chan)) {
			return -1;
		}
	}

	/* Wait for the connection to settle post-answer */
	ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n");
	if (ast_safe_sleep(chan, answait)) {
		return -1;
	}

	/* Attempt to receive the events */
	receive_ademco_event(chan, &event_head, signalling_type, &no_checksum);

	/* Events queued by receiver, write them all out here if so configured */
	if (!log_individual_events) {
		res = log_events(chan, signalling_type, event_head, no_checksum);
	}

	/* Do we exec a command line at the end? */
	if ((!res) && (!ast_strlen_zero(event_app)) && (event_head)) {
		ast_debug(1,"Alarmreceiver: executing: %s\n", event_app);
		ast_safe_system(event_app);
	}

	/* Free up the data allocated in our linked list */
	for (elp = event_head; (elp != NULL);) {
		efree = elp;
		elp = elp->next;
		ast_free(efree);
	}

	return 0;
}
示例#16
0
static int ices_exec(struct ast_channel *chan, void *data)
{
	int res=0;
	struct localuser *u;
	int fds[2];
	int ms = -1;
	int pid = -1;
	int flags;
	int oreadformat;
	struct timeval last;
	struct ast_frame *f;
	char filename[256]="";
	char *c;
	last.tv_usec = 0;
	last.tv_sec = 0;
	if (!data || !strlen(data)) {
		ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n");
		return -1;
	}
	if (pipe(fds)) {
		ast_log(LOG_WARNING, "Unable to create pipe\n");
		return -1;
	}
	flags = fcntl(fds[1], F_GETFL);
	fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
	
	LOCAL_USER_ADD(u);
	ast_stopstream(chan);

	if (chan->_state != AST_STATE_UP)
		res = ast_answer(chan);
		
	if (res) {
		close(fds[0]);
		close(fds[1]);
		ast_log(LOG_WARNING, "Answer failed!\n");
		return -1;
	}

	oreadformat = chan->readformat;
	res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
	if (res < 0) {
		close(fds[0]);
		close(fds[1]);
		ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
		return -1;
	}
	if (((char *)data)[0] == '/')
		strncpy(filename, (char *)data, sizeof(filename) - 1);
	else
		snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, (char *)data);
	/* Placeholder for options */		
	c = strchr(filename, '|');
	if (c)
		*c = '\0';	
	res = icesencode(filename, fds[0]);
	close(fds[0]);
	if (res >= 0) {
		pid = res;
		for (;;) {
			/* Wait for audio, and stream */
			ms = ast_waitfor(chan, -1);
			if (ms < 0) {
				ast_log(LOG_DEBUG, "Hangup detected\n");
				res = -1;
				break;
			}
			f = ast_read(chan);
			if (!f) {
				ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
				res = -1;
				break;
			}
			if (f->frametype == AST_FRAME_VOICE) {
				res = write(fds[1], f->data, f->datalen);
				if (res < 0) {
					if (errno != EAGAIN) {
						ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
						res = -1;
						break;
					}
				}
			}
			ast_frfree(f);
		}
	}
	close(fds[1]);
	LOCAL_USER_REMOVE(u);
	if (pid > -1)
		kill(pid, SIGKILL);
	if (!res && oreadformat)
		ast_set_read_format(chan, oreadformat);
	return res;
}
static int set_caps(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
		    const struct pjmedia_sdp_media *stream)
{
	RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, peer, NULL, ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, joint, NULL, ao2_cleanup);
	enum ast_media_type media_type = stream_to_media_type(session_media->stream_type);
	struct ast_rtp_codecs codecs = AST_RTP_CODECS_NULL_INIT;
	int fmts = 0;
	int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
		ast_format_cap_count(session->direct_media_cap);

	if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
	    !(peer = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT)) ||
	    !(joint = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
		ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n", session_media->stream_type);
		return -1;
	}

	/* get the endpoint capabilities */
	if (direct_media_enabled) {
		ast_format_cap_get_compatible(session->endpoint->media.codecs, session->direct_media_cap, caps);
		format_cap_only_type(caps, media_type);
	} else {
		ast_format_cap_append_from_cap(caps, session->endpoint->media.codecs, media_type);
	}

	/* get the capabilities on the peer */
	get_codecs(session, stream, &codecs);
	ast_rtp_codecs_payload_formats(&codecs, peer, &fmts);

	/* get the joint capabilities between peer and endpoint */
	ast_format_cap_get_compatible(caps, peer, joint);
	if (!ast_format_cap_count(joint)) {
		struct ast_str *usbuf = ast_str_alloca(64);
		struct ast_str *thembuf = ast_str_alloca(64);

		ast_rtp_codecs_payloads_destroy(&codecs);
		ast_log(LOG_NOTICE, "No joint capabilities for '%s' media stream between our configuration(%s) and incoming SDP(%s)\n",
			session_media->stream_type,
			ast_format_cap_get_names(caps, &usbuf),
			ast_format_cap_get_names(peer, &thembuf));
		return -1;
	}

	ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp),
				     session_media->rtp);

	ast_format_cap_append_from_cap(session->req_caps, joint, AST_MEDIA_TYPE_UNKNOWN);

	if (session->channel) {
		struct ast_format *fmt;

		ast_channel_lock(session->channel);
		ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN);
		ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(session->channel), AST_MEDIA_TYPE_UNKNOWN);
		ast_format_cap_remove_by_type(caps, media_type);

		/*
		 * XXX Historically we picked the "best" joint format to use
		 * and stuck with it.  It would be nice to just append the
		 * determined joint media capabilities to give translation
		 * more formats to choose from when necessary.  Unfortunately,
		 * there are some areas of the system where this doesn't work
		 * very well. (The softmix bridge in particular is reluctant
		 * to pick higher fidelity formats and has a problem with
		 * asymmetric sample rates.)
		 */
		fmt = ast_format_cap_get_format(joint, 0);
		ast_format_cap_append(caps, fmt, 0);

		/*
		 * Apply the new formats to the channel, potentially changing
		 * raw read/write formats and translation path while doing so.
		 */
		ast_channel_nativeformats_set(session->channel, caps);
		ast_set_read_format(session->channel, ast_channel_readformat(session->channel));
		ast_set_write_format(session->channel, ast_channel_writeformat(session->channel));
		ast_channel_unlock(session->channel);

		ao2_ref(fmt, -1);
	}

	ast_rtp_codecs_payloads_destroy(&codecs);
	return 0;
}
示例#18
0
static int ices_exec(struct ast_channel *chan, const char *data)
{
	int res = 0;
	int fds[2];
	int ms = -1;
	int pid = -1;
	int flags;
	struct ast_format oreadformat;
	struct ast_frame *f;
	char filename[256]="";
	char *c;

	ast_format_clear(&oreadformat);
	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n");
		return -1;
	}
	
	if (pipe(fds)) {
		ast_log(LOG_WARNING, "Unable to create pipe\n");
		return -1;
	}
	flags = fcntl(fds[1], F_GETFL);
	fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
	
	ast_stopstream(chan);

	if (ast_channel_state(chan) != AST_STATE_UP)
		res = ast_answer(chan);
		
	if (res) {
		close(fds[0]);
		close(fds[1]);
		ast_log(LOG_WARNING, "Answer failed!\n");
		return -1;
	}

	ast_format_copy(&oreadformat, ast_channel_readformat(chan));
	res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
	if (res < 0) {
		close(fds[0]);
		close(fds[1]);
		ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
		return -1;
	}
	if (((char *)data)[0] == '/')
		ast_copy_string(filename, (char *) data, sizeof(filename));
	else
		snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_CONFIG_DIR, (char *)data);
	/* Placeholder for options */		
	c = strchr(filename, '|');
	if (c)
		*c = '\0';	
	res = icesencode(filename, fds[0]);
	if (res >= 0) {
		pid = res;
		for (;;) {
			/* Wait for audio, and stream */
			ms = ast_waitfor(chan, -1);
			if (ms < 0) {
				ast_debug(1, "Hangup detected\n");
				res = -1;
				break;
			}
			f = ast_read(chan);
			if (!f) {
				ast_debug(1, "Null frame == hangup() detected\n");
				res = -1;
				break;
			}
			if (f->frametype == AST_FRAME_VOICE) {
				res = write(fds[1], f->data.ptr, f->datalen);
				if (res < 0) {
					if (errno != EAGAIN) {
						ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
						res = -1;
						ast_frfree(f);
						break;
					}
				}
			}
			ast_frfree(f);
		}
	}
	close(fds[0]);
	close(fds[1]);

	if (pid > -1)
		kill(pid, SIGKILL);
	if (!res && oreadformat.id)
		ast_set_read_format(chan, &oreadformat);

	return res;
}
示例#19
0
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;

}
示例#20
0
int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait)
{
	unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL };
	int msglens[5];
	int msgtypes[5];
	int newdatamode;
	int res;
	int x;
	int writeformat, readformat;
	int waitforswitch = 0;

	writeformat = chan->writeformat;
	readformat = chan->readformat;

	newdatamode = chan->adsicpe & ADSI_FLAG_DATAMODE;

	for (x=0;x<msglen;x+=(msg[x+1]+2)) {
		if (msg[x] == ADSI_SWITCH_TO_DATA) {
			ast_log(LOG_DEBUG, "Switch to data is sent!\n");
			waitforswitch++;
			newdatamode = ADSI_FLAG_DATAMODE;
		}
		
		if (msg[x] == ADSI_SWITCH_TO_VOICE) {
			ast_log(LOG_DEBUG, "Switch to voice is sent!\n");
			waitforswitch++;
			newdatamode = 0;
		}
	}
	msgs[0] = msg;

	msglens[0] = msglen;
	msgtypes[0] = msgtype;

	if (msglen > 253) {
		ast_log(LOG_WARNING, "Can't send ADSI message of %d bytes, too large\n", msglen);
		return -1;
	}

	ast_stopstream(chan);

	if (ast_set_write_format(chan, AST_FORMAT_ULAW)) {
		ast_log(LOG_WARNING, "Unable to set write format to ULAW\n");
		return -1;
	}

	if (ast_set_read_format(chan, AST_FORMAT_ULAW)) {
		ast_log(LOG_WARNING, "Unable to set read format to ULAW\n");
		if (writeformat) {
			if (ast_set_write_format(chan, writeformat)) 
				ast_log(LOG_WARNING, "Unable to restore write format to %d\n", writeformat);
		}
		return -1;
	}
	res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes);

	if (dowait) {
		ast_log(LOG_DEBUG, "Wait for switch is '%d'\n", waitforswitch);
		while(waitforswitch-- && ((res = ast_waitfordigit(chan, 1000)) > 0)) { res = 0; ast_log(LOG_DEBUG, "Waiting for 'B'...\n"); }
	}
	
	if (!res)
		chan->adsicpe = (chan->adsicpe & ~ADSI_FLAG_DATAMODE) | newdatamode;

	if (writeformat)
		ast_set_write_format(chan, writeformat);
	if (readformat)
		ast_set_read_format(chan, readformat);

	if (!res)
		res = ast_safe_sleep(chan, 100 );
	return res;
}
示例#21
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;
}
static int alarmreceiver_exec(struct ast_channel *chan, void *data)
{
	int res = 0;
	struct localuser *u;
	event_node_t *elp, *efree;
	char signalling_type[64] = "";

	event_node_t *event_head = NULL;

	LOCAL_USER_ADD(u);

	/* Set write and read formats to ULAW */

	if(option_verbose >= 4)
		ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Setting read and write formats to ULAW\n");

	if (ast_set_write_format(chan,AST_FORMAT_ULAW)){
		ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",chan->name);
		LOCAL_USER_REMOVE(u);
		return -1;
	}
	
	if (ast_set_read_format(chan,AST_FORMAT_ULAW)){
		ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",chan->name);
		LOCAL_USER_REMOVE(u);
		return -1;
	}

	/* Set default values for this invokation of the application */
	
	ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));


	/* Answer the channel if it is not already */

	if(option_verbose >= 4)
		ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Answering channel\n");

	if (chan->_state != AST_STATE_UP) {
	
		res = ast_answer(chan);
		
		if (res) {
			LOCAL_USER_REMOVE(u);
			return -1;
		}
	}

	/* Wait for the connection to settle post-answer */

	if(option_verbose >= 4)
		ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for connection to stabilize\n");

	res = ast_safe_sleep(chan, 1250);

	/* Attempt to receive the events */

	if(!res){
	
		/* Determine the protocol to receive in advance */
		/* Note: Ademco contact is the only one supported at this time */
		/* Others may be added later */
		
		if(!strcmp(signalling_type, ADEMCO_CONTACT_ID))
			receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head);
		else
			res = -1;
	}
	
		
	
	/* Events queued by receiver, write them all out here if so configured */

	if((!res) && (log_individual_events == 0)){
		res = log_events(chan, signalling_type, event_head);

	}

	/*
	* Do we exec a command line at the end?
	*/
	
	if((!res) && (!ast_strlen_zero(event_app)) && (event_head)){
		ast_log(LOG_DEBUG,"Alarmreceiver: executing: %s\n", event_app);
		ast_safe_system(event_app);
	}

	/*
	* Free up the data allocated in our linked list
	*/
		
	for(elp = event_head; (elp != NULL);){
		efree = elp;
		elp = elp->next;
		free(efree);
	}


	LOCAL_USER_REMOVE(u);

	return 0;
}
示例#23
0
int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
{
    int res;
    struct ast_filestream *writer;
    int rfmt;
    int totalms=0, total;

    struct ast_frame *f;
    struct ast_dsp *sildet;
    /* Play prompt if requested */
    if (prompt) {
        res = ast_streamfile(c, prompt, c->language);
        if (res < 0)
            return res;
        res = ast_waitstream(c,"");
        if (res < 0)
            return res;
    }
    rfmt = c->readformat;
    res = ast_set_read_format(c, 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();
    if (!sildet) {
        ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
        return -1;
    }
    writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
    if (!writer) {
        ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
        ast_dsp_free(sildet);
        return -1;
    }
    for(;;) {
        if ((res = ast_waitfor(c, 2000)) < 0) {
            ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
            break;
        }
        if (res) {
            f = ast_read(c);
            if (!f) {
                ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
                break;
            }
            if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
                /* Ended happily with DTMF */
                ast_frfree(f);
                break;
            } else if (f->frametype == AST_FRAME_VOICE) {
                ast_dsp_silence(sildet, f, &total);
                if (total > silence) {
                    /* Ended happily with silence */
                    ast_frfree(f);
                    break;
                }
                totalms += f->samples / 8;
                if (totalms > maxsec * 1000) {
                    /* Ended happily with too much stuff */
                    ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
                    ast_frfree(f);
                    break;
                }
            }
            ast_frfree(f);
        }
    }
    res = ast_set_read_format(c, rfmt);
    if (res)
        ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
    ast_dsp_free(sildet);
    ast_closestream(writer);
    return 0;
}
示例#24
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;
}
示例#25
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;
}
示例#26
0
static int conf_run(struct ast_channel *chan, int confno, int confflags)
{
	int fd;
	struct dahdi_confinfo dahdic;
	struct ast_frame *f;
	struct ast_channel *c;
	struct ast_frame fr;
	int outfd;
	int ms;
	int nfds;
	int res;
	int flags;
	int retrydahdi;
	int origfd;
	int ret = -1;
	char input[4];
	int ic = 0;
	
	struct dahdi_bufferinfo bi;
	char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
	char *buf = __buf + AST_FRIENDLY_OFFSET;
	
	/* Set it into U-law mode (write) */
	if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
		ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
		goto outrun;
	}
	
	/* Set it into U-law mode (read) */
	if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
		ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
		goto outrun;
	}
	ast_indicate(chan, -1);
	retrydahdi = strcasecmp(chan->tech->type, "DAHDI");
 dahdiretry:
	origfd = chan->fds[0];
	if (retrydahdi) {
		fd = open("/dev/dahdi/pseudo", O_RDWR);
		if (fd < 0) {
			ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
			goto outrun;
		}
		/* Make non-blocking */
		flags = fcntl(fd, F_GETFL);
		if (flags < 0) {
			ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
			ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		/* Setup buffering information */
		memset(&bi, 0, sizeof(bi));
		bi.bufsize = CONF_SIZE;
		bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
		bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
		bi.numbufs = 4;
		if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
			ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		nfds = 1;
	} else {
		/* XXX Make sure we're not running on a pseudo channel XXX */
		fd = chan->fds[0];
		nfds = 0;
	}
	memset(&dahdic, 0, sizeof(dahdic));
	/* Check to see if we're in a conference... */
	dahdic.chan = 0;
	if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
		ast_log(LOG_WARNING, "Error getting conference\n");
		close(fd);
		goto outrun;
	}
	if (dahdic.confmode) {
		/* Whoa, already in a conference...  Retry... */
		if (!retrydahdi) {
			ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
			retrydahdi = 1;
			goto dahdiretry;
		}
	}
	memset(&dahdic, 0, sizeof(dahdic));
	/* Add us to the conference */
	dahdic.chan = 0;
	dahdic.confno = confno;
	dahdic.confmode = DAHDI_CONF_MONITORBOTH;

	if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
		ast_log(LOG_WARNING, "Error setting conference\n");
		close(fd);
		goto outrun;
	}
	ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan->name, confno);

	for (;;) {
		outfd = -1;
		ms = -1;
		c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
		if (c) {
			if (c->fds[0] != origfd) {
				if (retrydahdi) {
					/* Kill old pseudo */
					close(fd);
				}
				ast_debug(1, "Ooh, something swapped out under us, starting over\n");
				retrydahdi = 0;
				goto dahdiretry;
			}
			f = ast_read(c);
			if (!f) {
				break;
			}
			if (f->frametype == AST_FRAME_DTMF) {
				if (f->subclass == '#') {
					ret = 0;
					break;
				} else if (f->subclass == '*') {
					ret = -1;
					break;
				} else {
					input[ic++] = f->subclass;
				}
				if (ic == 3) {
					input[ic++] = '\0';
					ic = 0;
					ret = atoi(input);
					ast_verb(3, "DAHDIScan: change channel to %d\n", ret);
					break;
				}
			}

			if (fd != chan->fds[0]) {
				if (f->frametype == AST_FRAME_VOICE) {
					if (f->subclass == AST_FORMAT_ULAW) {
						/* Carefully write */
						careful_write(fd, f->data.ptr, f->datalen);
					} else {
						ast_log(LOG_WARNING, "Huh?  Got a non-ulaw (%d) frame in the conference\n", f->subclass);
					}
				}
			}
			ast_frfree(f);
		} else if (outfd > -1) {
			res = read(outfd, buf, CONF_SIZE);
			if (res > 0) {
				memset(&fr, 0, sizeof(fr));
				fr.frametype = AST_FRAME_VOICE;
				fr.subclass = AST_FORMAT_ULAW;
				fr.datalen = res;
				fr.samples = res;
				fr.data.ptr = buf;
				fr.offset = AST_FRIENDLY_OFFSET;
				if (ast_write(chan, &fr) < 0) {
					ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
					/* break; */
				}
			} else {
				ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
			}
		}
	}
	if (f) {
		ast_frfree(f);
	}
	if (fd != chan->fds[0]) {
		close(fd);
	} else {
		/* Take out of conference */
		/* Add us to the conference */
		dahdic.chan = 0;
		dahdic.confno = 0;
		dahdic.confmode = 0;
		if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
			ast_log(LOG_WARNING, "Error setting conference\n");
		}
	}

 outrun:

	return ret;
}
示例#27
0
static int txfax_exec(struct ast_channel *chan, void *data)
{
    int res = 0;
    char source_file[256];
    char *x;
    char *s;
    char *t;
    char *v;
    int option;
    int len;
    t30_state_t fax;
    int calling_party;
    int verbose;
    int samples;
    
    struct localuser *u;
    struct ast_frame *inf = NULL;
    struct ast_frame outf;

    int original_read_fmt;
    int original_write_fmt;
    
    uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
    uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;

    if (chan == NULL)
    {
        ast_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n");
        return -1;
    }

    span_set_message_handler(span_message);

    /* The next few lines of code parse out the filename and header from the input string */
    if (data == NULL)
    {
        /* No data implies no filename or anything is present */
        ast_log(LOG_WARNING, "Txfax requires an argument (filename)\n");
        return -1;
    }
    
    calling_party = FALSE;
    verbose = FALSE;
    source_file[0] = '\0'; 

    for (option = 0, v = s = data;  v;  option++, s++)
    {
        t = s;
        v = strchr(s, '|');
        s = (v)  ?  v  :  s + strlen(s);
        strncpy((char *) buf, t, s - t);
        buf[s - t] = '\0';
        if (option == 0)
        {
            /* The first option is always the file name */
            len = s - t;
            if (len > 255)
                len = 255;
            strncpy(source_file, t, len);
            source_file[len] = '\0';
        }
        else if (strncmp("caller", t, s - t) == 0)
        {
            calling_party = TRUE;
        }
        else if (strncmp("debug", t, s - t) == 0)
        {
            verbose = TRUE;
        }
    }

    /* Done parsing */

    LOCAL_USER_ADD(u);

    if (chan->_state != AST_STATE_UP)
    {
        /* Shouldn't need this, but checking to see if channel is already answered
         * Theoretically asterisk should already have answered before running the app */
        res = ast_answer(chan);
    }
    
    if (!res)
    {
        original_read_fmt = chan->readformat;
        if (original_read_fmt != AST_FORMAT_SLINEAR)
        {
            res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
            if (res < 0)
            {
                ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
                return -1;
            }
        }
        original_write_fmt = chan->writeformat;
        if (original_write_fmt != AST_FORMAT_SLINEAR)
        {
            res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
            if (res < 0)
            {
                ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
                res = ast_set_read_format(chan, original_read_fmt);
                if (res)
                    ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
                return -1;
            }
        }
        fax_init(&fax, calling_party, NULL);
        if (verbose)
	    fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;

        x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
        if (x  &&  x[0])
            t30_set_local_ident(&fax, x);
        x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO");
        if (x  &&  x[0])
            t30_set_header_info(&fax, x);
        t30_set_tx_file(&fax, source_file, -1, -1);
        //t30_set_phase_b_handler(&fax, phase_b_handler, chan);
        //t30_set_phase_d_handler(&fax, phase_d_handler, chan);
        t30_set_phase_e_handler(&fax, phase_e_handler, chan);
        while (ast_waitfor(chan, -1) > -1)
        {
            inf = ast_read(chan);
            if (inf == NULL)
            {
                res = -1;
                break;
            }
            if (inf->frametype == AST_FRAME_VOICE)
            {
                if (fax_rx(&fax, inf->data, inf->samples))
                    break;
                samples = (inf->samples <= MAX_BLOCK_SIZE)  ?  inf->samples  :  MAX_BLOCK_SIZE;
                len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples);
                if (len)
                {
                    memset(&outf, 0, sizeof(outf));
                    outf.frametype = AST_FRAME_VOICE;
                    outf.subclass = AST_FORMAT_SLINEAR;
                    outf.datalen = len*sizeof(int16_t);
                    outf.samples = len;
                    outf.data = &buf[AST_FRIENDLY_OFFSET];
                    outf.offset = AST_FRIENDLY_OFFSET;
                    if (ast_write(chan, &outf) < 0)
                    {
                        ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
                        break;
                    }
                }
            }
            ast_frfree(inf);
        }
        if (inf == NULL)
        {
            ast_log(LOG_DEBUG, "Got hangup\n");
            res = -1;
        }
        if (original_read_fmt && original_read_fmt != AST_FORMAT_SLINEAR)
        {
            res = ast_set_read_format(chan, original_read_fmt);
            if (res)
                ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
        }
        if (original_write_fmt && original_write_fmt != AST_FORMAT_SLINEAR)
        {
            res = ast_set_write_format(chan, original_write_fmt);
            if (res)
                ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name);
        }
        fax_release(&fax);
    }
    else
    {
        ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
    }
    LOCAL_USER_REMOVE(u);
    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;
}
示例#29
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;
}
示例#30
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;
}