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