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

📄 iax.c

📁 来自网络的iaxclient的协议栈源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			return -1;		cur = cur->next;	}	return 0;}int iax_get_netstats(struct iax_session *session, int *rtt, struct iax_netstat *local, struct iax_netstat *remote){	jb_info stats;	if(!iax_session_valid(session)) return -1;	*rtt = session->pingtime;	*remote = session->remote_netstats;	jb_getinfo(session->jb, &stats);	local->jitter = stats.jitter;	/* XXX: should be short-term loss pct.. */	if(stats.frames_in == 0) stats.frames_in = 1;	local->losspct = stats.losspct/1000;	local->losscnt = stats.frames_lost;	local->packets = stats.frames_in;	local->delay = stats.current - stats.min;	local->dropped = stats.frames_dropped;	local->ooo = stats.frames_ooo;	return 0;}#ifdef USE_VOICE_TS_PREDICTIONstatic void add_ms(struct timeval *tv, int ms){	tv->tv_usec += ms * 1000;	if(tv->tv_usec > 1000000) {		tv->tv_usec -= 1000000;		tv->tv_sec++;	}	if(tv->tv_usec < 0) {		tv->tv_usec += 1000000;		tv->tv_sec--;	}}#endifstatic int calc_timestamp(struct iax_session *session, unsigned int ts, struct ast_frame *f){	int ms;	struct timeval tv;	int voice = 0;	int video = 0;	int genuine = 0;	if ( f && f->frametype == AST_FRAME_VOICE )	{		voice = 1;	} else if ( f && f->frametype == AST_FRAME_VIDEO )	{		video = 1;	} else if (!f || f->frametype == AST_FRAME_IAX)	{		genuine = 1;	}	/* If this is the first packet we're sending, get our	   offset now. */	if (!session->offset.tv_sec && !session->offset.tv_usec)		gettimeofday(&session->offset, NULL);	/* If the timestamp is specified, just use their specified	   timestamp no matter what.  Usually this is done for	   special cases.  */	if (ts)	{		if ( f && session )			session->lastsent = ts;		return ts;	}	/* Otherwise calculate the timestamp from the current time */	gettimeofday(&tv, NULL);	/* Calculate the number of milliseconds since we sent the first packet */	ms = (tv.tv_sec - session->offset.tv_sec) * 1000 +		 (tv.tv_usec - session->offset.tv_usec) / 1000;	if (ms < 0)		ms = 0;	if(voice) {#ifdef USE_VOICE_TS_PREDICTION		/* If we haven't most recently sent silence, and we're		 * close in time, use predicted time */		if(session->notsilenttx && abs(ms - session->nextpred) <= 240) {			/* Adjust our txcore, keeping voice and non-voice			 * synchronized */			add_ms(&session->offset, (int)(ms - session->nextpred)/10);			if(!session->nextpred)				session->nextpred = ms;			ms = session->nextpred;		} else {			/* in this case, just use the actual time, since			 * we're either way off (shouldn't happen), or we're			 * ending a silent period -- and seed the next predicted			 * time.  Also, round ms to the next multiple of			 * frame size (so our silent periods are multiples			 * of frame size too) */			int diff = ms % (f->samples / 8);			if(diff)				ms += f->samples/8 - diff;			session->nextpred = ms;		}		session->notsilenttx = 1;#else		if(ms <= session->lastsent)			ms = session->lastsent + 3;#endif	} else if (video) {		if ((unsigned int)ms <= session->lastsent)			ms = session->lastsent + 3;	} else {		/* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking)		   if appropriate unless it's a genuine frame */		if (genuine) {			if ((unsigned int)ms <= session->lastsent)				ms = session->lastsent + 3;		} else if (abs(ms - session->lastsent) <= 240) {			ms = session->lastsent + 3;		}	}	/* Record the last sent packet for future reference */	/* unless an AST_FRAME_IAX */	if (!genuine)		session->lastsent = ms;#ifdef USE_VOICE_TS_PREDICTION	/* set next predicted ts based on 8khz samples */	if(voice)	    session->nextpred = session->nextpred + f->samples / 8;#endif	return ms;}static unsigned char get_n_bits_at(unsigned char *data, int n, int bit){	int byte = bit / 8;       /* byte containing first bit */	int rem = 8 - (bit % 8);  /* remaining bits in first byte */	unsigned char ret = 0;	if (n <= 0 || n > 8)		return 0;	if (rem < n) {		ret = (data[byte] << (n - rem));		ret |= (data[byte + 1] >> (8 - n + rem));	} else {		ret = (data[byte] >> (rem - n));	}	return (ret & (0xff >> (8 - n)));}static int speex_get_wb_sz_at(unsigned char *data, int len, int bit){	static int SpeexWBSubModeSz[] = {		0, 36, 112, 192,		352, 0, 0, 0 };	int off = bit;	unsigned char c;	/* skip up to two wideband frames */	if (((len * 8 - off) >= 5) &&		get_n_bits_at(data, 1, off)) {		c = get_n_bits_at(data, 3, off + 1);		off += SpeexWBSubModeSz[c];		if (((len * 8 - off) >= 5) &&			get_n_bits_at(data, 1, off)) {			c = get_n_bits_at(data, 3, off + 1);			off += SpeexWBSubModeSz[c];			if (((len * 8 - off) >= 5) &&				get_n_bits_at(data, 1, off)) {				/* too many in a row */				DEBU(G "\tCORRUPT too many wideband streams in a row\n");				return -1;			}		}	}	return off - bit;}static int speex_get_samples(unsigned char *data, int len){	static int SpeexSubModeSz[] = {		0, 43, 119, 160,		220, 300, 364, 492,		79, 0, 0, 0,		0, 0, 0, 0 };	static int SpeexInBandSz[] = {		1, 1, 4, 4,		4, 4, 4, 4,		8, 8, 16, 16,		32, 32, 64, 64 };	int bit = 0;	int cnt = 0;	int off = 0;	unsigned char c;	DEBU(G "speex_get_samples(%d)\n", len);	while ((len * 8 - bit) >= 5) {		/* skip wideband frames */		off = speex_get_wb_sz_at(data, len, bit);		if (off < 0)  {			DEBU(G "\tERROR reading wideband frames\n");			break;		}		bit += off;		if ((len * 8 - bit) < 5) {			DEBU(G "\tERROR not enough bits left after wb\n");			break;		}		/* get control bits */		c = get_n_bits_at(data, 5, bit);		DEBU(G "\tCONTROL: %d at %d\n", c, bit);		bit += 5;		if (c == 15) {			DEBU(G "\tTERMINATOR\n");			break;		} else if (c == 14) {			/* in-band signal; next 4 bits contain signal id */			c = get_n_bits_at(data, 4, bit);			bit += 4;			DEBU(G "\tIN-BAND %d bits\n", SpeexInBandSz[c]);			bit += SpeexInBandSz[c];		} else if (c == 13) {			/* user in-band; next 5 bits contain msg len */			c = get_n_bits_at(data, 5, bit);			bit += 5;			DEBU(G "\tUSER-BAND %d bytes\n", c);			bit += c * 8;		} else if (c > 8) {			DEBU(G "\tUNKNOWN sub-mode %d\n", c);			break;		} else {			/* skip number bits for submode (less the 5 control bits) */			DEBU(G "\tSUBMODE %d %d bits\n", c, SpeexSubModeSz[c]);			bit += SpeexSubModeSz[c] - 5;			cnt += 160; /* new frame */		}	}	DEBU(G "\tSAMPLES: %d\n", cnt);	return cnt;}static inline int get_interp_len(int format){	return (format == AST_FORMAT_ILBC) ? 30 : 20;}static int get_sample_cnt(struct iax_event *e){	int cnt = 0;	/*	 * In the case of zero length frames, do not return a cnt of 0	 */	if ( e->datalen == 0 ) {		return get_interp_len( e->subclass ) * 8;	}	switch (e->subclass) {	case AST_FORMAT_SPEEX:		cnt = speex_get_samples(e->data, e->datalen);		break;	case AST_FORMAT_G723_1:		cnt = 240;		/* FIXME Not always the case */		break;	case AST_FORMAT_ILBC:		cnt = 240 * (e->datalen / 50);		break;	case AST_FORMAT_GSM:		cnt = 160 * (e->datalen / 33);		break;	case AST_FORMAT_G729A:		cnt = 160 * (e->datalen / 20);		break;	case AST_FORMAT_SLINEAR:		cnt = e->datalen / 2;		break;	case AST_FORMAT_LPC10:		cnt = 22 * 8 + (((char *)(e->data))[7] & 0x1) * 8;		break;	case AST_FORMAT_ULAW:	case AST_FORMAT_ALAW:		cnt = e->datalen;		break;	case AST_FORMAT_ADPCM:	case AST_FORMAT_G726:		cnt = e->datalen * 2;		break;	default:		return 0;	}	return cnt;}static int iax_xmit_frame(struct iax_frame *f){	int res;#ifdef DEBUG_SUPPORT	struct ast_iax2_full_hdr *h = (struct ast_iax2_full_hdr *)(f->data);	if (ntohs(h->scallno) & IAX_FLAG_FULL)		iax_showframe(f, NULL, 0, f->transfer ?				&(f->session->transfer) :				&(f->session->peeraddr),				f->datalen - sizeof(struct ast_iax2_full_hdr));#endif	/* Send the frame raw */	res = f->session->sendto(netfd, (const char *) f->data, f->datalen, IAX_SOCKOPTS,			f->transfer ? (struct sockaddr *)&(f->session->transfer) :			(struct sockaddr *)&(f->session->peeraddr),			sizeof(f->session->peeraddr));	return res;}static int iax_reliable_xmit(struct iax_frame *f){	struct iax_frame *fc;	struct ast_iax2_full_hdr *fh;	fh = (struct ast_iax2_full_hdr *) f->data;	if (!fh->type) {		return -2;	}	fc = (struct iax_frame *)malloc(sizeof(struct iax_frame));	if (fc) {		/* Make a copy of the frame */		memcpy(fc, f, sizeof(struct iax_frame));		/* And a copy of the data if applicable */		if (!fc->data || !fc->datalen) {			IAXERROR "No frame data?");			DEBU(G "No frame data?\n");			return -1;		} else {			fc->data = (char *)malloc(fc->datalen);			if (!fc->data) {				DEBU(G "Out of memory\n");				IAXERROR "Out of memory\n");				return -1;			}			memcpy(fc->data, f->data, f->datalen);			iax_sched_add(NULL, fc, NULL, NULL, fc->retrytime);			return iax_xmit_frame(fc);		}	} else		return -1;}void iax_set_networking(iax_sendto_t st, iax_recvfrom_t rf){	iax_sendto = st;	iax_recvfrom = rf;}void iax_set_jb_target_extra( long value ){	/* store in jb_target_extra, a static global */	jb_target_extra = value ;}int iax_init(int preferredportno){	int portno = preferredportno;	if (iax_recvfrom == (iax_recvfrom_t)recvfrom)	{		struct sockaddr_in sin;		socklen_t sinlen;		int flags;		int bufsize = 256 * 1024;		if (netfd > -1)		{			/* Okay, just don't do anything */			DEBU(G "Already initialized.");			return 0;		}		netfd = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);		if (netfd < 0)		{			DEBU(G "Unable to allocate UDP socket\n");			IAXERROR "Unable to allocate UDP socket\n");			return -1;		}		if (preferredportno == 0)			preferredportno = IAX_DEFAULT_PORTNO;		if (preferredportno < 0)			preferredportno = 0;		sin.sin_family = AF_INET;		sin.sin_addr.s_addr = 0;		sin.sin_port = htons((short)preferredportno);		if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0)		{#if defined(WIN32)  ||  defined(_WIN32_WCE)			if (WSAGetLastError() == WSAEADDRINUSE)#else			if (errno == EADDRINUSE)#endif			{				/*the port is already in use, so bind to a free port chosen by the IP stack*/				DEBU(G "Unable to bind to preferred port - port is in use. Trying to bind to a free one");				sin.sin_port = htons((short)0);				if (bind(netfd, (struct sockaddr *) &sin, sizeof(sin)) < 0)				{					IAXERROR "Unable to bind UDP socket\n");					return -1;				}			} else			{				IAXERROR "Unable to bind UDP socket\n");				return -1;			}		}		sinlen = sizeof(sin);		if (getsockname(netfd, (struct sockaddr *) &sin, &sinlen) < 0)		{			close(netfd);			netfd = -1;			DEBU(G "Unable to figure out what I'm bound to.");			IAXERROR "Unable to determine bound port number.");			return -1;		}#if defined(WIN32)  ||  defined(_WIN32_WCE)		flags = 1;		if (ioctlsocket(netfd,FIONBIO,(unsigned long *) &flags))		{			closesocket(netfd);			netfd = -1;			DEBU(G "Unable to set non-blocking mode.");			IAXERROR "Unable to set non-blocking mode.");			return -1;		}#else		if ((flags = fcntl(netfd, F_GETFL)) < 0)		{			close(netfd);			netfd = -1;			DEBU(G "Unable to retrieve socket flags.");			IAXERROR "Unable to retrieve socket flags.");			return -1;		}		if (fcntl(netfd, F_SETFL, flags | O_NONBLOCK) < 0)		{			close(netfd);			netfd = -1;			DEBU(G "Unable to set non-blocking mode.");			IAXERROR "Unable to set non-blocking mode.");			return -1;		}#endif		/* Mihai: increase UDP socket buffers to avoid packet loss. */		if (setsockopt(netfd, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize,					sizeof(bufsize)) < 0)		{			DEBU(G "Unable to set buffer size.");			IAXERROR "Unable to set buffer size.");		}		portno = ntohs(sin.sin_port);		DEBU(G "Started on port %d\n", portno);	}	srand((unsigned int)time(0));	callnums = rand() % 32767 + 1;	transfer_id = rand() % 32767 + 1;	return portno;}static void destroy_session(struct iax_session *session);static void convert_reply(char *out, unsigned char *in){	int x;	for (x=0;x<16;x++)		out += sprintf(out, "%2.2x", (int)in[x]);}static unsigned char compress_subclass(int subclass){

⌨️ 快捷键说明

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