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

📄 iax.c

📁 ppciaxclient softphone
💻 C
📖 第 1 页 / 共 5 页
字号:


int iax_time_to_next_event(void)
{
	struct timeval tv;
	struct iax_sched *cur = schedq;
	int ms, min = 999999999;
	
	/* If there are no pending events, we don't need to timeout */
	if (!cur)
		return -1;
	gettimeofday(&tv, NULL);
	while(cur) {
		ms = (cur->when.tv_sec - tv.tv_sec) * 1000 +
		     (cur->when.tv_usec - tv.tv_usec) / 1000;
		if (ms < min)
			min = ms;
		cur = cur->next;
	}
	if (min < 0)
		min = 0;
	return min;
}

struct iax_session *iax_session_new(void)
{
	struct iax_session *s;
	s = (struct iax_session *)malloc(sizeof(struct iax_session));
	if (s) {
		memset(s, 0, sizeof(struct iax_session));
		/* Initialize important fields */
		s->voiceformat = -1;
		s->svoiceformat = -1;
		/* Default pingtime to 30 ms */
		s->pingtime = 30;
		/* XXX Not quite right -- make sure it's not in use, but that won't matter
	           unless you've had at least 65k calls.  XXX */
		s->callno = callnums++;
		if (callnums > 32767)
			callnums = 1;
		s->peercallno = 0;
		s->transferpeer = 0;		/* for attended transfer */
		s->next = sessions;
		s->sendto = iax_sendto;
		s->pingid = -1;
#ifdef NEWJB
		s->jb = jb_new();
		{
			jb_conf jbconf;
			jbconf.max_jitterbuf = 0;
			jbconf.resync_threshold = 1000;
			jbconf.max_contig_interp = 0;
			jb_setconf(s->jb, &jbconf);
		}
#endif
		sessions = s;
	}
	return s;
}

static int iax_session_valid(struct iax_session *session)
{
	/* Return -1 on a valid iax session pointer, 0 on a failure */
	struct iax_session *cur = sessions;
	while(cur) {
		if (session == cur)
			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) {

  if(!iax_session_valid(session)) return -1;

  *rtt = session->pingtime;

  *remote = session->remote_netstats;

#ifdef NEWJB
  {
      jb_info stats;
      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;
  }
#endif
  return 0;
}

static 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--;
  }
}

static int calc_timestamp(struct iax_session *session, unsigned int ts, struct ast_frame *f)
{
	int ms;
	struct timeval tv;
	int voice = 0;
	int genuine = 0;

	if (f && f->frametype == AST_FRAME_VOICE) {
		voice = 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)
		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; 
		}
#else
		if(ms <= session->lastsent)
			ms = session->lastsent + 3;
#endif
		session->notsilenttx = 1;
	} else {
		/* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking) 
		   if appropriate unless it's a genuine frame */
		if (genuine) {
			if (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 int get_sample_cnt(struct iax_event *e)
{
	int cnt = 0;
	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)
{
	struct ast_iax2_full_hdr *h = (f->data);
	/* Send the frame raw */
#ifdef DEBUG_SUPPORT
	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

	return 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));
}

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)
		return -1;
	if (!fh->type) {
		DEBU(G "Asked to reliably transmit a non-packet.  Crashing.\n");
		*((char *)0)=0;
	}
	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(sendto_t st, recvfrom_t rf)
{
	iax_sendto = st;
	iax_recvfrom = rf;
}

int iax_init(int preferredportno)
{
	int portno = preferredportno;
	struct sockaddr_in sin;
	unsigned int sinlen;
	int flags;
#ifdef _POCKETPC_
iax_recvfrom = recvfrom;
iax_sendto = sendto;
#endif
	if(iax_recvfrom == recvfrom) {
	    if (netfd > -1) {
		    /* Sokay, just don't do anything */
		    DEBU(G "Already initialized.");
		    return 0;
	    }
	    netfd = 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) {
		    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) {
			    DEBU(G "Unable to bind to preferred port.  Using random one instead.");
		    }
	    }
	    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.");
	    }*/
#ifdef	WIN32
	    flags = 1;
	    if (ioctlsocket(netfd,FIONBIO,(unsigned long *) &flags)) {
#ifdef _WIN32_WCE
			closesocket(netfd);
#else
		    _close(netfd);
#endif
		    netfd = -1;
		    DEBU(G "Unable to set non-blocking mode.");
		    IAXERROR "Unable to set non-blocking mode.");

⌨️ 快捷键说明

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