⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chan_agent.c

📁 Asterisk中信道部分的源码 。。。。
💻 C
📖 第 1 页 / 共 5 页
字号:
		p->dead = 0;	return p;}/*! * Deletes an agent after doing some clean up. * Further documentation: How safe is this function ? What state should the agent be to be cleaned. * \param p Agent to be deleted. * \returns Always 0. */static int agent_cleanup(struct agent_pvt *p){	struct ast_channel *chan = p->owner;	p->owner = NULL;	chan->tech_pvt = NULL;	p->app_sleep_cond = 1;	/* Release ownership of the agent to other threads (presumably running the login app). */	ast_mutex_unlock(&p->app_lock);	if (chan)		ast_channel_free(chan);	if (p->dead) {		ast_mutex_destroy(&p->lock);		ast_mutex_destroy(&p->app_lock);		free(p);        }	return 0;}static int check_availability(struct agent_pvt *newlyavailable, int needlock);static int agent_answer(struct ast_channel *ast){	ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");	return -1;}static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock){	char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;	char filename[AST_MAX_BUF];	int res = -1;	if (!p)		return -1;	if (!ast->monitor) {		snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);		/* substitute . for - */		if ((pointer = strchr(filename, '.')))			*pointer = '-';		snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);		ast_monitor_start(ast, recordformat, tmp, needlock);		ast_monitor_setjoinfiles(ast, 1);		snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);#if 0		ast_verbose("name is %s, link is %s\n",tmp, tmp2);#endif		if (!ast->cdr)			ast->cdr = ast_cdr_alloc();		ast_cdr_setuserfield(ast, tmp2);		res = 0;	} else		ast_log(LOG_ERROR, "Recording already started on that call.\n");	return res;}static int agent_start_monitoring(struct ast_channel *ast, int needlock){	return __agent_start_monitoring(ast, ast->tech_pvt, needlock);}static struct ast_frame *agent_read(struct ast_channel *ast){	struct agent_pvt *p = ast->tech_pvt;	struct ast_frame *f = NULL;	static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };	const char *status;	ast_mutex_lock(&p->lock); 	CHECK_FORMATS(ast, p);	if (p->chan) {		ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);		p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;		f = ast_read(p->chan);	} else		f = &ast_null_frame;	if (!f) {		/* If there's a channel, hang it up (if it's on a callback) make it NULL */		if (p->chan) {			p->chan->_bridge = NULL;			/* Note that we don't hangup if it's not a callback because Asterisk will do it			   for us when the PBX instance that called login finishes */			if (!ast_strlen_zero(p->loginchan)) {				if (p->chan)					ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);				if (p->owner->_state != AST_STATE_UP) {					int howlong = time(NULL) - p->start;					if (p->autologoff && howlong > p->autologoff) {						long logintime = time(NULL) - p->loginstart;						p->loginstart = 0;							ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);						agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");						if (persistent_agents)							dump_agents();					}				}				status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");				if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {					long logintime = time(NULL) - p->loginstart;					p->loginstart = 0;					ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);					agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");				}				ast_hangup(p->chan);				if (p->wrapuptime && p->acknowledged)					p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));			}			p->chan = NULL;			p->inherited_devicestate = -1;			ast_device_state_changed("Agent/%s", p->agent);			p->acknowledged = 0;		} 	} else { 		/* if acknowledgement is not required, and the channel is up, we may have missed 		   an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 		if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP))  			p->acknowledged = 1; 		switch (f->frametype) { 		case AST_FRAME_CONTROL: 			if (f->subclass == AST_CONTROL_ANSWER) { 				if (p->ackcall) { 					if (option_verbose > 2) 						ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name); 					/* Don't pass answer along */ 					ast_frfree(f); 					f = &ast_null_frame; 				} else { 					p->acknowledged = 1; 					/* Use the builtin answer frame for the 					   recording start check below. */ 					ast_frfree(f); 					f = &answer_frame; 				} 			} 			break;		case AST_FRAME_DTMF_BEGIN:			/*ignore DTMF begin's as it can cause issues with queue announce files*/			if((!p->acknowledged && f->subclass == '#') || (f->subclass == '*' && endcall)){				ast_frfree(f);				f = &ast_null_frame;			}			break; 		case AST_FRAME_DTMF_END: 			if (!p->acknowledged && (f->subclass == '#')) { 				if (option_verbose > 2) 					ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name); 				p->acknowledged = 1; 				ast_frfree(f); 				f = &answer_frame; 			} else if (f->subclass == '*' && endcall) { 				/* terminates call */ 				ast_frfree(f); 				f = NULL; 			} 			break; 		case AST_FRAME_VOICE: 		case AST_FRAME_VIDEO: 			/* don't pass voice or video until the call is acknowledged */ 			if (!p->acknowledged) { 				ast_frfree(f); 				f = &ast_null_frame; 			}		default:			/* pass everything else on through */			break;  		}  	}	CLEANUP(ast,p);	if (p->chan && !p->chan->_bridge) {		if (strcasecmp(p->chan->tech->type, "Local")) {			p->chan->_bridge = ast;			if (p->chan)				ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);		}	}	ast_mutex_unlock(&p->lock);	if (recordagentcalls && f == &answer_frame)		agent_start_monitoring(ast,0);	return f;}static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen){	struct agent_pvt *p = ast->tech_pvt;	int res = -1;	ast_mutex_lock(&p->lock);	if (p->chan) 		res = ast_channel_sendhtml(p->chan, subclass, data, datalen);	ast_mutex_unlock(&p->lock);	return res;}static int agent_sendtext(struct ast_channel *ast, const char *text){	struct agent_pvt *p = ast->tech_pvt;	int res = -1;	ast_mutex_lock(&p->lock);	if (p->chan) 		res = ast_sendtext(p->chan, text);	ast_mutex_unlock(&p->lock);	return res;}static int agent_write(struct ast_channel *ast, struct ast_frame *f){	struct agent_pvt *p = ast->tech_pvt;	int res = -1;	CHECK_FORMATS(ast, p);	ast_mutex_lock(&p->lock);	if (!p->chan) 		res = 0;	else {		if ((f->frametype != AST_FRAME_VOICE) ||		    (f->frametype != AST_FRAME_VIDEO) ||		    (f->subclass == p->chan->writeformat)) {			res = ast_write(p->chan, f);		} else {			ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 				f->frametype == AST_FRAME_VOICE ? "audio" : "video",				ast->name, p->chan->name);			res = 0;		}	}	CLEANUP(ast, p);	ast_mutex_unlock(&p->lock);	return res;}static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan){	struct agent_pvt *p = newchan->tech_pvt;	ast_mutex_lock(&p->lock);	if (p->owner != oldchan) {		ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);		ast_mutex_unlock(&p->lock);		return -1;	}	p->owner = newchan;	ast_mutex_unlock(&p->lock);	return 0;}static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen){	struct agent_pvt *p = ast->tech_pvt;	int res = -1;	ast_mutex_lock(&p->lock);	if (p->chan && !ast_check_hangup(p->chan))		res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;	else		res = 0;	ast_mutex_unlock(&p->lock);	return res;}static int agent_digit_begin(struct ast_channel *ast, char digit){	struct agent_pvt *p = ast->tech_pvt;	ast_mutex_lock(&p->lock);	if (p->chan) {		ast_senddigit_begin(p->chan, digit);	}	ast_mutex_unlock(&p->lock);	return 0;}static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration){	struct agent_pvt *p = ast->tech_pvt;	ast_mutex_lock(&p->lock);	if (p->chan) {		ast_senddigit_end(p->chan, digit, duration);	}	ast_mutex_unlock(&p->lock);	return 0;}static int agent_call(struct ast_channel *ast, char *dest, int timeout){	struct agent_pvt *p = ast->tech_pvt;	int res = -1;	int newstate=0;	ast_mutex_lock(&p->lock);	p->acknowledged = 0;	if (!p->chan) {		if (p->pending) {			ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");			newstate = AST_STATE_DIALING;			res = 0;		} else {			ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");			res = -1;		}		ast_mutex_unlock(&p->lock);		if (newstate)			ast_setstate(ast, newstate);		return res;	} else if (!ast_strlen_zero(p->loginchan)) {		time(&p->start);		/* Call on this agent */		if (option_verbose > 2)			ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);		ast_set_callerid(p->chan,			ast->cid.cid_num, ast->cid.cid_name, NULL);		ast_channel_inherit_variables(ast, p->chan);		res = ast_call(p->chan, p->loginchan, 0);		CLEANUP(ast,p);		ast_mutex_unlock(&p->lock);		return res;	}	ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);	if (option_debug > 2)		ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);	res = ast_streamfile(p->chan, beep, p->chan->language);	if (option_debug > 2)		ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res);	if (!res) {		res = ast_waitstream(p->chan, "");		if (option_debug > 2)			ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res);	}	if (!res) {		res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));		if (option_debug > 2)			ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res);		if (res)			ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));	} else {		/* Agent hung-up */		p->chan = NULL;		p->inherited_devicestate = -1;		ast_device_state_changed("Agent/%s", p->agent);	}	if (!res) {		res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));		if (option_debug > 2)			ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res);		if (res)			ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));	}	if(!res) {		/* Call is immediately up, or might need ack */		if (p->ackcall > 1)			newstate = AST_STATE_RINGING;		else {			newstate = AST_STATE_UP;			if (recordagentcalls)				agent_start_monitoring(ast, 0);			p->acknowledged = 1;		}		res = 0;	}	CLEANUP(ast, p);	ast_mutex_unlock(&p->lock);	if (newstate)		ast_setstate(ast, newstate);	return res;}/*! \brief store/clear the global variable that stores agentid based on the callerid */static void set_agentbycallerid(const char *callerid, const char *agent){	char buf[AST_MAX_BUF];	/* if there is no Caller ID, nothing to do */	if (ast_strlen_zero(callerid))		return;	snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);	pbx_builtin_setvar_helper(NULL, buf, agent);}/*! \brief return the channel or base channel if one exists.  This function assumes the channel it is called on is already locked */struct ast_channel* agent_get_base_channel(struct ast_channel *chan){	struct agent_pvt *p = NULL;	struct ast_channel *base = chan;	/* chan is locked by the calling function */	if (!chan || !chan->tech_pvt) {		ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) with a tech_pvt (0x%ld) to get a base channel.\n", (long)chan, (chan)?(long)chan->tech_pvt:(long)NULL);		return NULL;	}	p = chan->tech_pvt;	if (p->chan) 		base = p->chan;	return base;}int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base){	struct agent_pvt *p = NULL;		if (!chan || !base) {		ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);		return -1;	}	p = chan->tech_pvt;	if (!p) {		ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);		return -1;	}	p->chan = base;	return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -