📄 iax.c
字号:
/*
* libiax: An implementation of Inter-Asterisk eXchange
*
* Copyright (C) 2001, Linux Support Services, Inc.
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU Lesser (Library) General Public License
*/
#ifdef _WIN32_WCE
#include <windows.h>
#include <stdio.h>
#include <string.h>
void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
#define close closesocket
#define strdup _strdup
#define strerror(err) NULL
#define INLINE __inline
#define errno 0
#undef SNOM_HACK
#endif
#ifdef WIN32
#undef __STRICT_ANSI__ //for strdup with ms
#include <string.h>
#ifndef _WIN32_WCE
#include <process.h>
#include <fcntl.h>
#include <io.h>
#include <errno.h>
#include <windows.h>
#include <winsock.h>
#include <time.h>
#include <stdlib.h>
#include <malloc.h>
#include <stdarg.h>
#include <stdio.h>
#endif
#include <limits.h>
#define snprintf _snprintf
#if defined(_MSC_VER) && !defined(_WIN32_WCE)
#define close _close
#define INLINE __inline
#endif
void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
#elif !defined(_WIN32_WCE) && !defined(WIN32)
/*#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <stdlib.h>*/
#ifdef __GNUC__
#define __USE_SVID
#endif
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#ifndef MACOSX
#include <malloc.h>
#ifndef SOLARIS
#include <error.h>
#endif
#endif
#endif
#ifdef NEWJB
#include "jitterbuf.h"
#endif
#include "iax-client.h"
#include "md5.h"
/*
work around jitter-buffer shrinking in asterisk:
channels/chan_iax2.c:schedule_delivery() shrinks jitter buffer by 2.
this causes frames timestamped 1ms apart to ( sometimes ) be delivered
out of order, and results in garbled audio. our temporary fix is to increase
the minimum number of ( timestamped ) milliseconds between frames to 3 ( 2 + 1 ).
*/
#define IAX_MIN_TIMESTAMP_INCREMENT 3
/* Define socket options for IAX2 sockets, based on platform
* availability of flags */
#ifdef WIN32
#define IAX_SOCKOPTS 0
#else
#ifdef MACOSX
#define IAX_SOCKOPTS MSG_DONTWAIT
#else
#ifdef SOLARIS
#define IAX_SOCKOPTS MSG_DONTWAIT
#else /* Linux and others */
#define IAX_SOCKOPTS MSG_DONTWAIT | MSG_NOSIGNAL
#endif
#endif
#endif
#ifdef SNOM_HACK
/* The snom phone seems to improperly execute memset in some cases */
//#include "../../snom_phonecore2/include/snom_memset.h"
#endif
/* Voice TS Prediction causes libiax2 to clean up the timestamps on
* outgoing frames. It works best with either continuous voice, or
* callers who call iax_send_cng to indicate DTX for silence */
#define USE_VOICE_TS_PREDICTION
/* Define Voice Smoothing to try to make some judgements and adjust timestamps
on incoming packets to what they "ought to be" */
#define VOICE_SMOOTHING
#undef VOICE_SMOOTHING
/* Define Drop Whole Frames to make IAX shrink its jitter buffer by dropping entire
frames rather than simply delivering them faster. Dropping encoded frames,
before they're decoded, usually leads to better results than dropping
decoded frames. */
#define DROP_WHOLE_FRAMES
#define MIN_RETRY_TIME 10
#define MAX_RETRY_TIME 4000
#define MEMORY_SIZE 1000
#define TRANSFER_NONE 0
#define TRANSFER_BEGIN 1
#define TRANSFER_READY 2
#define TRANSFER_REL 3
/* No more than 4 seconds of jitter buffer */
static int max_jitterbuffer = 4000;
/* No more than 50 extra milliseconds of jitterbuffer than needed */
static int max_extra_jitterbuffer = 50;
/* To use or not to use the jitterbuffer */
static int iax_use_jitterbuffer = 1;
/* UDP Socket (file descriptor) */
static int netfd = -1;
/* Max timeouts */
static int maxretries = 10;
/* Dropcount (in per-MEMORY_SIZE) usually percent */
static int iax_dropcount = 3;
/* external global networking replacements */
static sendto_t iax_sendto = sendto;
static recvfrom_t iax_recvfrom = recvfrom;
/* ping interval (seconds) */
static int ping_time = 10;
static void send_ping(void *session);
struct iax_session {
/* Private data */
void *pvt;
/* session-local Sendto function */
sendto_t sendto;
/* Is voice quelched (e.g. hold) */
int quelch;
/* Last received voice format */
int voiceformat;
/* Last transmitted voice format */
int svoiceformat;
/* Per session capability */
int capability;
/* Last received timestamp */
unsigned int last_ts;
/* Last transmitted timestamp */
unsigned int lastsent;
/* Last transmitted voice timestamp */
unsigned int lastvoicets;
/* Next predicted voice ts */
unsigned int nextpred;
/* True if the last voice we transmitted was not silence/CNG */
int notsilenttx;
/* Our last measured ping time */
unsigned int pingtime;
/* Address of peer */
struct sockaddr_in peeraddr;
/* Our call number */
int callno;
/* Peer's call number */
int peercallno;
/* Our next outgoing sequence number */
unsigned char oseqno;
/* Next sequence number they have not yet acknowledged */
unsigned char rseqno;
/* Our last received incoming sequence number */
unsigned char iseqno;
/* Last acknowledged sequence number */
unsigned char aseqno;
/* Peer supported formats */
int peerformats;
/* Time value that we base our transmission on */
struct timeval offset;
/* Time value we base our delivery on */
struct timeval rxcore;
/* History of lags */
int history[MEMORY_SIZE];
/* Current base jitterbuffer */
int jitterbuffer;
/* Informational jitter */
int jitter;
/* Measured lag */
int lag;
/* Current link state */
int state;
/* Peer name */
char peer[MAXSTRLEN];
/* Default Context */
char context[MAXSTRLEN];
/* Caller ID if available */
char callerid[MAXSTRLEN];
/* DNID */
char dnid[MAXSTRLEN];
/* Requested Extension */
char exten[MAXSTRLEN];
/* Expected Username */
char username[MAXSTRLEN];
/* Expected Secret */
char secret[MAXSTRLEN];
/* permitted authentication methods */
char methods[MAXSTRLEN];
/* MD5 challenge */
char challenge[12];
#ifdef VOICE_SMOOTHING
unsigned int lastts;
#endif
/* Refresh if applicable */
int refresh;
/* ping scheduler id */
int pingid;
/* Transfer stuff */
struct sockaddr_in transfer;
int transferring;
int transfercallno;
int transferid;
int transferpeer; /* for attended transfer */
int transfer_moh; /* for music on hold while performing attended transfer */
#ifdef NEWJB
jitterbuf *jb;
#endif
struct iax_netstat remote_netstats;
/* For linking if there are multiple connections */
struct iax_session *next;
};
char iax_errstr[256];
#define IAXERROR snprintf(iax_errstr, sizeof(iax_errstr),
#ifdef DEBUG_SUPPORT
#ifdef DEBUG_DEFAULT
static int debug = 1;
#else
static int debug = 0;
#endif
void iax_enable_debug(void)
{
debug = 1;
}
void iax_disable_debug(void)
{
debug = 0;
}
void iax_set_private(struct iax_session *s, void *ptr)
{
s->pvt = ptr;
}
void *iax_get_private(struct iax_session *s)
{
return s->pvt;
}
void iax_set_sendto(struct iax_session *s, sendto_t ptr)
{
s->sendto = ptr;
}
/* This is a little strange, but to debug you call DEBU(G "Hello World!\n"); */
#ifdef WIN32
#define G __FILE__, __LINE__,
#else
#define G __FILE__, __LINE__, __PRETTY_FUNCTION__,
#endif
#define DEBU __debug
#ifdef WIN32
static int __debug(char *file, int lineno, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (debug) {
fprintf(stderr, "%s line %d: ", file, lineno);
vfprintf(stderr, fmt, args);
}
va_end(args);
return 0;
}
#else
static int __debug(char *file, int lineno, char *func, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (debug) {
fprintf(stderr, "%s line %d in %s: ", file, lineno, func);
vfprintf(stderr, fmt, args);
}
va_end(args);
return 0;
}
#endif
#else /* No debug support */
#ifdef WIN32
#define DEBU
#else
#define DEBU(fmt...) \
do {} while(0)
#endif
#define G
#endif
typedef void (*sched_func)(void *);
struct iax_sched {
/* These are scheduled things to be delivered */
struct timeval when;
/* If event is non-NULL then we're delivering an event */
struct iax_event *event;
/* If frame is non-NULL then we're transmitting a frame */
struct iax_frame *frame;
/* If func is non-NULL then we should call it */
sched_func func;
/* and pass it this argument */
void *arg;
/* Easy linking */
struct iax_sched *next;
};
static struct iax_sched *schedq = NULL;
static struct iax_session *sessions = NULL;
static int callnums = 1;
static int transfer_id = 1; /* for attended transfer */
static int inaddrcmp(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
{
return (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) || (sin1->sin_port != sin2->sin_port);
}
static int iax_sched_add(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int ms)
{
/* Schedule event to be delivered to the client
in ms milliseconds from now, or a reliable frame to be retransmitted */
struct iax_sched *sched, *cur, *prev = NULL;
if (!event && !frame && !func) {
DEBU(G "No event, no frame, no func? what are we scheduling?\n");
return -1;
}
sched = (struct iax_sched*)malloc(sizeof(struct iax_sched));
if (sched) {
memset(sched, 0, sizeof(struct iax_sched));
gettimeofday(&sched->when, NULL);
sched->when.tv_sec += (ms / 1000);
ms = ms % 1000;
sched->when.tv_usec += (ms * 1000);
if (sched->when.tv_usec > 1000000) {
sched->when.tv_usec -= 1000000;
sched->when.tv_sec++;
}
sched->event = event;
sched->frame = frame;
sched->func = func;
sched->arg = arg;
/* Put it in the list, in order */
cur = schedq;
while(cur && ((cur->when.tv_sec < sched->when.tv_sec) ||
((cur->when.tv_usec <= sched->when.tv_usec) &&
(cur->when.tv_sec == sched->when.tv_sec)))) {
prev = cur;
cur = cur->next;
}
sched->next = cur;
if (prev) {
prev->next = sched;
} else {
schedq = sched;
}
return 0;
} else {
DEBU(G "Out of memory!\n");
return -1;
}
}
static int iax_sched_del(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int all)
{
struct iax_sched *cur, *tmp, *prev = NULL;
cur = schedq;
while (cur) {
if (cur->event == event && cur->frame == frame && cur->func == func && cur->arg == arg) {
if (prev)
prev->next = cur->next;
else
schedq = cur->next;
tmp = cur;
cur = cur->next;
free(tmp);
if (!all)
break;
} else {
prev = cur;
cur = cur->next;
}
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -