📄 iax.c
字号:
} 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 = LONG_MAX; local->losspct = stats.frames_lost * 100 / stats.frames_in; 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 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->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; int sinlen; int flags; 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)) { _close(netfd); netfd = -1; DEBU(G "Unable to set non-blocking mode."); IAXERROR "Unable to set non-blocking mode."); } #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."); } 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."); }#endif portno = ntohs(sin.sin_port); } srand(time(NULL)); callnums = rand() % 32767 + 1; transfer_id = rand() % 32767 + 1; DEBU(G "Started on port %d\n", portno); 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){ int x; int power=-1; /* If it's 128 or smaller, just return it */ if (subclass < IAX_FLAG_SC_LOG) return subclass; /* Otherwise find its power */ for (x = 0; x < IAX_MAX_SHIFT; x++) { if (subclass & (1 << x)) { if (power > -1) { DEBU(G "Can't compress subclass %d\n", subclass); return 0; } else power = x; } } return power | IAX_FLAG_SC_LOG;}static int iax_send(struct iax_session *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final) { /* Queue a packet for delivery on a given private structure. Use "ts" for timestamp, or calculate if ts is 0. Send immediately without retransmission or delayed, with retransmission */ struct ast_iax2_full_hdr *fh; struct ast_iax2_mini_hdr *mh; unsigned char buf[5120]; struct iax_frame *fr; int res; int sendmini=0; unsigned int lastsent; unsigned int fts; if (!pvt) { IAXERROR "No private structure for packet?\n"); return -1; } /* this must come before the next call to calc_timestamp() since calc_timestamp() will change lastsent to the returned value */ lastsent = pvt->lastsent; /* Calculate actual timestamp */ fts = calc_timestamp(pvt, ts, f); if (((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L)) /* High two bits are the same on timestamp, or sending on a trunk */ && (f->frametype == AST_FRAME_VOICE) /* is a voice frame */ && (f->subclass == pvt->svoiceformat) /* is the same type */ ) { /* Force immediate rather than delayed transmission */ now = 1; /* Mark that mini-style frame is appropriate */ sendmini = 1; } /* Allocate an iax_frame */ if (now) { fr = (struct iax_frame *) buf; } else fr = iax_frame_new(DIRECTION_OUTGRESS, f->datalen); if (!fr) { IAXERROR "Out of memory\n"); return -1; } /* Copy our prospective frame into our immediate or retransmitted wrapper */ iax_frame_wrap(fr, f); fr->ts = fts; if (!fr->ts) { IAXERROR "timestamp is 0?\n"); if (!now) iax_frame_free(fr); return -1; } fr->callno = pvt->callno; fr->transfer = transfer; fr->final = final; fr->session = pvt; if (!sendmini) { /* We need a full frame */ if (seqno > -1) fr->oseqno = seqno; else fr->oseqno = pvt->oseqno++; fr->iseqno = pvt->iseqno; fh = (struct ast_iax2_full_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_full_hdr)); fh->scallno = htons(fr->callno | IAX_FLAG_FULL); fh->ts = htonl(fr->ts); fh->oseqno = fr->oseqno; if (transfer) { fh->iseqno = 0; } else fh->iseqno = fr->iseqno; /* Keep track of the last thing we've acknowledged */ pvt->aseqno = fr->iseqno; fh->type = fr->af.frametype & 0xFF; fh->csub = compress_subclass(fr->af.subclass); if (transfer) { fr->dcallno = pvt->transfercallno; } else fr->dcallno = pvt->peercallno; fh->dcallno = htons(fr->dcallno); fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_full_hdr); fr->data = fh; fr->retries = maxretries; /* Retry after 2x the ping time has passed */ fr->retrytime = pvt->pingtime * 2; if (fr->retrytime < MIN_RETRY_TIME) fr->retrytime = MIN_RETRY_TIME; if (fr->retrytime > MAX_RETRY_TIME) fr->retrytime = MAX_RETRY_TIME; /* Acks' don't get retried */ if ((f->frametype == AST_FRAME_IAX) && (f->subclass == IAX_COMMAND_ACK)) fr->retries = -1; if (f->frametype == AST_FRAME_VOICE) { pvt->svoiceformat = f->subclass; } if (now) { res = iax_xmit_frame(fr); } else res = iax_reliable_xmit(fr); } else { /* Mini-frames have no sequence number */ fr->oseqno = -1; fr->iseqno = -1; /* Mini frame will do */ mh = (struct ast_iax2_mini_hdr *)(((char *)fr->af.data) - sizeof(struct ast_iax2_mini_hdr)); mh->callno = htons(fr->callno); mh->ts = htons(fr->ts & 0xFFFF); fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr); fr->data = mh; fr->retries = -1; res = iax_xmit_frame(fr); } return res;}#if 0static int iax_predestroy(struct iax_session *pvt){ if (!pvt) { return -1; } if (!pvt->alreadygone) { /* No more pings or lagrq's */ if (pvt->pingid > -1) ast_sched_del(sched, pvt->pingid); if (pvt->lagid > -1) ast_sched_del(sched, pvt->lagid); if (pvt->autoid > -1) ast_sched_del(sched, pvt->autoid); if (pvt->initid > -1) ast_sched_del(sched, pvt->initid); pvt->pingid = -1; pvt->lagid = -1; pvt->autoid = -1; pvt->initid = -1; pvt->alreadygone = 1; } return 0;}#endifstatic int __send_command(struct iax_session *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno, int now, int transfer, int final, int samples){ struct ast_frame f; f.frametype = type; f.subclass = command; f.datalen = datalen; f.samples = samples; f.mallocd = 0; f.offset = 0;#ifdef __GNUC__ f.src = __FUNCTION__;#else f.src = __FILE__;#endif f.data = data; return iax_send(i, &f, ts, seqno, now, transfer, final);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -