📄 iax.c
字号:
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 + -