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

📄 chan_phone.c

📁 Asterisk中信道部分的源码 。。。。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Asterisk -- An open source telephony toolkit. * * Copyright (C) 1999 - 2005, Digium, Inc. * * Mark Spencer <markster@digium.com> * * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2. See the LICENSE file * at the top of the source tree. *//*! \file * * \brief Generic Linux Telephony Interface driver * * \author Mark Spencer <markster@digium.com> *  * \ingroup channel_drivers *//*** MODULEINFO	<depend>ixjuser</depend> ***/#include "asterisk.h"ASTERISK_FILE_VERSION(__FILE__, "$Revision: 106235 $")#include <stdio.h>#include <string.h>#include <ctype.h>#include <sys/socket.h>#include <sys/time.h>#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <arpa/inet.h>#include <fcntl.h>#include <sys/ioctl.h>#include <signal.h>#ifdef HAVE_LINUX_COMPILER_H#include <linux/compiler.h>#endif#include <linux/telephony.h>/* Still use some IXJ specific stuff */#include <linux/version.h>#include <linux/ixjuser.h>#include "asterisk/lock.h"#include "asterisk/channel.h"#include "asterisk/config.h"#include "asterisk/logger.h"#include "asterisk/module.h"#include "asterisk/pbx.h"#include "asterisk/options.h"#include "asterisk/utils.h"#include "asterisk/callerid.h"#include "asterisk/causes.h"#include "asterisk/stringfields.h"#include "asterisk/musiconhold.h"#include "DialTone.h"#ifdef QTI_PHONEJACK_TJ_PCI	/* check for the newer quicknet driver v.3.1.0 which has this symbol */#define QNDRV_VER 310#else#define QNDRV_VER 100#endif#if QNDRV_VER > 100#ifdef __linux__#define IXJ_PHONE_RING_START(x)	ioctl(p->fd, PHONE_RING_START, &x);#else /* FreeBSD and others */#define IXJ_PHONE_RING_START(x)	ioctl(p->fd, PHONE_RING_START, x);#endif /* __linux__ */#else	/* older driver */#define IXJ_PHONE_RING_START(x)	ioctl(p->fd, PHONE_RING_START, &x);#endif#define DEFAULT_CALLER_ID "Unknown"#define PHONE_MAX_BUF 480#define DEFAULT_GAIN 0x100static const char tdesc[] = "Standard Linux Telephony API Driver";static const char config[] = "phone.conf";/* Default context for dialtone mode */static char context[AST_MAX_EXTENSION] = "default";/* Default language */static char language[MAX_LANGUAGE] = "";static int echocancel = AEC_OFF;static int silencesupression = 0;static int prefformat = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW;/* Protect the interface list (of phone_pvt's) */AST_MUTEX_DEFINE_STATIC(iflock);/* Protect the monitoring thread, so only one process can kill or start it, and not   when it's doing something critical. */AST_MUTEX_DEFINE_STATIC(monlock);/* Boolean value whether the monitoring thread shall continue. */static unsigned int monitor;   /* This is the thread for the monitor which checks for input on the channels   which are not currently in use.  */static pthread_t monitor_thread = AST_PTHREADT_NULL;static int restart_monitor(void);/* The private structures of the Phone Jack channels are linked for   selecting outgoing channels */   #define MODE_DIALTONE 	1#define MODE_IMMEDIATE	2#define MODE_FXO	3#define MODE_FXS        4#define MODE_SIGMA      5static struct phone_pvt {	int fd;							/* Raw file descriptor for this device */	struct ast_channel *owner;		/* Channel we belong to, possibly NULL */	int mode;						/* Is this in the  */	int lastformat;					/* Last output format */	int lastinput;					/* Last input format */	int ministate;					/* Miniature state, for dialtone mode */	char dev[256];					/* Device name */	struct phone_pvt *next;			/* Next channel in list */	struct ast_frame fr;			/* Frame */	char offset[AST_FRIENDLY_OFFSET];	char buf[PHONE_MAX_BUF];					/* Static buffer for reading frames */	int obuflen;	int dialtone;	int txgain, rxgain;             /* gain control for playing, recording  */									/* 0x100 - 1.0, 0x200 - 2.0, 0x80 - 0.5 */	int cpt;						/* Call Progress Tone playing? */	int silencesupression;	char context[AST_MAX_EXTENSION];	char obuf[PHONE_MAX_BUF * 2];	char ext[AST_MAX_EXTENSION];	char language[MAX_LANGUAGE];	char cid_num[AST_MAX_EXTENSION];	char cid_name[AST_MAX_EXTENSION];} *iflist = NULL;static char cid_num[AST_MAX_EXTENSION];static char cid_name[AST_MAX_EXTENSION];static struct ast_channel *phone_request(const char *type, int format, void *data, int *cause);static int phone_digit_begin(struct ast_channel *ast, char digit);static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int duration);static int phone_call(struct ast_channel *ast, char *dest, int timeout);static int phone_hangup(struct ast_channel *ast);static int phone_answer(struct ast_channel *ast);static struct ast_frame *phone_read(struct ast_channel *ast);static int phone_write(struct ast_channel *ast, struct ast_frame *frame);static struct ast_frame *phone_exception(struct ast_channel *ast);static int phone_send_text(struct ast_channel *ast, const char *text);static int phone_fixup(struct ast_channel *old, struct ast_channel *new);static int phone_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);static const struct ast_channel_tech phone_tech = {	.type = "Phone",	.description = tdesc,	.capabilities = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW,	.requester = phone_request,	.send_digit_begin = phone_digit_begin,	.send_digit_end = phone_digit_end,	.call = phone_call,	.hangup = phone_hangup,	.answer = phone_answer,	.read = phone_read,	.write = phone_write,	.exception = phone_exception,	.indicate = phone_indicate,	.fixup = phone_fixup};static struct ast_channel_tech phone_tech_fxs = {	.type = "Phone",	.description = tdesc,	.requester = phone_request,	.send_digit_begin = phone_digit_begin,	.send_digit_end = phone_digit_end,	.call = phone_call,	.hangup = phone_hangup,	.answer = phone_answer,	.read = phone_read,	.write = phone_write,	.exception = phone_exception,	.write_video = phone_write,	.send_text = phone_send_text,	.indicate = phone_indicate,	.fixup = phone_fixup};static struct ast_channel_tech *cur_tech;static int phone_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen){	struct phone_pvt *p = chan->tech_pvt;	int res=-1;	ast_log(LOG_DEBUG, "Requested indication %d on channel %s\n", condition, chan->name);	switch(condition) {	case AST_CONTROL_FLASH:		ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);		usleep(320000);		ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);			p->lastformat = -1;			res = 0;			break;	case AST_CONTROL_HOLD:		ast_moh_start(chan, data, NULL);		break;	case AST_CONTROL_UNHOLD:		ast_moh_stop(chan);		break;	case AST_CONTROL_SRCUPDATE:		res = 0;		break;	default:		ast_log(LOG_WARNING, "Condition %d is not supported on channel %s\n", condition, chan->name);	}	return res;}static int phone_fixup(struct ast_channel *old, struct ast_channel *new){	struct phone_pvt *pvt = old->tech_pvt;	if (pvt && pvt->owner == old)		pvt->owner = new;	return 0;}static int phone_digit_begin(struct ast_channel *chan, char digit){	/* XXX Modify this callback to let Asterisk support controlling the length of DTMF */	return 0;}static int phone_digit_end(struct ast_channel *ast, char digit, unsigned int duration){	struct phone_pvt *p;	int outdigit;	p = ast->tech_pvt;	ast_log(LOG_DEBUG, "Dialed %c\n", digit);	switch(digit) {	case '0':	case '1':	case '2':	case '3':	case '4':	case '5':	case '6':	case '7':	case '8':	case '9':		outdigit = digit - '0';		break;	case '*':		outdigit = 11;		break;	case '#':		outdigit = 12;		break;	case 'f':	/*flash*/	case 'F':		ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_ON_HOOK);		usleep(320000);		ioctl(p->fd, IXJCTL_PSTN_SET_STATE, PSTN_OFF_HOOK);		p->lastformat = -1;		return 0;	default:		ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);		return -1;	}	ast_log(LOG_DEBUG, "Dialed %d\n", outdigit);	ioctl(p->fd, PHONE_PLAY_TONE, outdigit);	p->lastformat = -1;	return 0;}static int phone_call(struct ast_channel *ast, char *dest, int timeout){	struct phone_pvt *p;	PHONE_CID cid;	time_t UtcTime;	struct tm tm;	int start;	time(&UtcTime);	ast_localtime(&UtcTime, &tm, NULL);	memset(&cid, 0, sizeof(PHONE_CID));	if(&tm != NULL) {		snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1));		snprintf(cid.day, sizeof(cid.day),     "%02d", tm.tm_mday);		snprintf(cid.hour, sizeof(cid.hour),   "%02d", tm.tm_hour);		snprintf(cid.min, sizeof(cid.min),     "%02d", tm.tm_min);	}	/* the standard format of ast->callerid is:  "name" <number>, but not always complete */	if (ast_strlen_zero(ast->cid.cid_name))		strcpy(cid.name, DEFAULT_CALLER_ID);	else		ast_copy_string(cid.name, ast->cid.cid_name, sizeof(cid.name));	if (ast->cid.cid_num) 		ast_copy_string(cid.number, ast->cid.cid_num, sizeof(cid.number));	p = ast->tech_pvt;	if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {		ast_log(LOG_WARNING, "phone_call called on %s, neither down nor reserved\n", ast->name);		return -1;	}	if (option_debug)		ast_log(LOG_DEBUG, "Ringing %s on %s (%d)\n", dest, ast->name, ast->fds[0]);	start = IXJ_PHONE_RING_START(cid);	if (start == -1)		return -1;		if (p->mode == MODE_FXS) {		char *digit = strchr(dest, '/');		if (digit)		{		  digit++;		  while (*digit)		    phone_digit_end(ast, *digit++, 0);		}	}   	ast_setstate(ast, AST_STATE_RINGING);	ast_queue_control(ast, AST_CONTROL_RINGING);	return 0;}static int phone_hangup(struct ast_channel *ast){	struct phone_pvt *p;	p = ast->tech_pvt;	if (option_debug)		ast_log(LOG_DEBUG, "phone_hangup(%s)\n", ast->name);	if (!ast->tech_pvt) {		ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");		return 0;	}	/* XXX Is there anything we can do to really hang up except stop recording? */	ast_setstate(ast, AST_STATE_DOWN);	if (ioctl(p->fd, PHONE_REC_STOP))		ast_log(LOG_WARNING, "Failed to stop recording\n");	if (ioctl(p->fd, PHONE_PLAY_STOP))		ast_log(LOG_WARNING, "Failed to stop playing\n");	if (ioctl(p->fd, PHONE_RING_STOP))		ast_log(LOG_WARNING, "Failed to stop ringing\n");	if (ioctl(p->fd, PHONE_CPT_STOP))		ast_log(LOG_WARNING, "Failed to stop sounds\n");	/* If it's an FXO, hang them up */	if (p->mode == MODE_FXO) {		if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK)) 			ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",ast->name, strerror(errno));	}	/* If they're off hook, give a busy signal */	if (ioctl(p->fd, PHONE_HOOKSTATE)) {		if (option_debug)			ast_log(LOG_DEBUG, "Got hunghup, giving busy signal\n");		ioctl(p->fd, PHONE_BUSY);		p->cpt = 1;	}	p->lastformat = -1;	p->lastinput = -1;	p->ministate = 0;	p->obuflen = 0;	p->dialtone = 0;	memset(p->ext, 0, sizeof(p->ext));	((struct phone_pvt *)(ast->tech_pvt))->owner = NULL;	ast_module_unref(ast_module_info->self);	if (option_verbose > 2) 		ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name);	ast->tech_pvt = NULL;	ast_setstate(ast, AST_STATE_DOWN);	restart_monitor();	return 0;}static int phone_setup(struct ast_channel *ast){	struct phone_pvt *p;	p = ast->tech_pvt;	ioctl(p->fd, PHONE_CPT_STOP);	/* Nothing to answering really, just start recording */	if (ast->rawreadformat == AST_FORMAT_G723_1) {		/* Prefer g723 */		ioctl(p->fd, PHONE_REC_STOP);		if (p->lastinput != AST_FORMAT_G723_1) {			p->lastinput = AST_FORMAT_G723_1;			if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) {				ast_log(LOG_WARNING, "Failed to set codec to g723.1\n");				return -1;			}		}	} else if (ast->rawreadformat == AST_FORMAT_SLINEAR) {		ioctl(p->fd, PHONE_REC_STOP);		if (p->lastinput != AST_FORMAT_SLINEAR) {			p->lastinput = AST_FORMAT_SLINEAR;			if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) {				ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n");				return -1;			}		}	} else if (ast->rawreadformat == AST_FORMAT_ULAW) {		ioctl(p->fd, PHONE_REC_STOP);		if (p->lastinput != AST_FORMAT_ULAW) {			p->lastinput = AST_FORMAT_ULAW;			if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) {				ast_log(LOG_WARNING, "Failed to set codec to uLaw\n");				return -1;			}		}	} else if (p->mode == MODE_FXS) {		ioctl(p->fd, PHONE_REC_STOP);		if (p->lastinput != ast->rawreadformat) {			p->lastinput = ast->rawreadformat;			if (ioctl(p->fd, PHONE_REC_CODEC, ast->rawreadformat)) {				ast_log(LOG_WARNING, "Failed to set codec to %d\n", 					ast->rawreadformat);				return -1;			}		}	} else {		ast_log(LOG_WARNING, "Can't do format %s\n", ast_getformatname(ast->rawreadformat));		return -1;	}	if (ioctl(p->fd, PHONE_REC_START)) {		ast_log(LOG_WARNING, "Failed to start recording\n");		return -1;	}	/* set the DTMF times (the default is too short) */	ioctl(p->fd, PHONE_SET_TONE_ON_TIME, 300);	ioctl(p->fd, PHONE_SET_TONE_OFF_TIME, 200);	return 0;}static int phone_answer(struct ast_channel *ast){	struct phone_pvt *p;	p = ast->tech_pvt;	/* In case it's a LineJack, take it off hook */	if (p->mode == MODE_FXO) {		if (ioctl(p->fd, PHONE_PSTN_SET_STATE, PSTN_OFF_HOOK)) 			ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n", ast->name, strerror(errno));		else			ast_log(LOG_DEBUG, "Took linejack off hook\n");	}	phone_setup(ast);	if (option_debug)		ast_log(LOG_DEBUG, "phone_answer(%s)\n", ast->name);	ast->rings = 0;	ast_setstate(ast, AST_STATE_UP);	return 0;}#if 0static char phone_2digit(char c)

⌨️ 快捷键说明

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