mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-19 19:52:48 +00:00
Add remainder of rtp fixes, iax2 patch (bug #3961)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5654 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -859,48 +859,6 @@ static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer, cons
|
|||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_samples(struct ast_frame *f)
|
|
||||||
{
|
|
||||||
int samples=0;
|
|
||||||
switch(f->subclass) {
|
|
||||||
case AST_FORMAT_SPEEX:
|
|
||||||
samples = 160; /* XXX Not necessarily true XXX */
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_G723_1:
|
|
||||||
samples = 240 /* XXX Not necessarily true XXX */;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_ILBC:
|
|
||||||
samples = 240 * (f->datalen / 50);
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_GSM:
|
|
||||||
samples = 160 * (f->datalen / 33);
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_G729A:
|
|
||||||
samples = 160 * (f->datalen / 20);
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_SLINEAR:
|
|
||||||
samples = f->datalen / 2;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_LPC10:
|
|
||||||
samples = 22 * 8;
|
|
||||||
samples += (((char *)(f->data))[7] & 0x1) * 8;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_ULAW:
|
|
||||||
samples = f->datalen;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_ALAW:
|
|
||||||
samples = f->datalen;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_ADPCM:
|
|
||||||
case AST_FORMAT_G726:
|
|
||||||
samples = f->datalen *2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ast_log(LOG_WARNING, "Don't know how to calculate samples on %d packets\n", f->subclass);
|
|
||||||
}
|
|
||||||
return samples;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct iax_frame *iaxfrdup2(struct iax_frame *fr)
|
static struct iax_frame *iaxfrdup2(struct iax_frame *fr)
|
||||||
{
|
{
|
||||||
/* Malloc() a copy of a frame */
|
/* Malloc() a copy of a frame */
|
||||||
@@ -2347,7 +2305,7 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
|
|||||||
|
|
||||||
if(fr->af.frametype == AST_FRAME_VOICE) {
|
if(fr->af.frametype == AST_FRAME_VOICE) {
|
||||||
type = JB_TYPE_VOICE;
|
type = JB_TYPE_VOICE;
|
||||||
len = get_samples(&fr->af)/8;
|
len = ast_codec_get_samples(&fr->af) / 8;
|
||||||
} else if(fr->af.frametype == AST_FRAME_CNG) {
|
} else if(fr->af.frametype == AST_FRAME_CNG) {
|
||||||
type = JB_TYPE_SILENCE;
|
type = JB_TYPE_SILENCE;
|
||||||
}
|
}
|
||||||
@@ -6240,7 +6198,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
|
|||||||
f.mallocd = 0;
|
f.mallocd = 0;
|
||||||
f.offset = 0;
|
f.offset = 0;
|
||||||
if (f.datalen && (f.frametype == AST_FRAME_VOICE))
|
if (f.datalen && (f.frametype == AST_FRAME_VOICE))
|
||||||
f.samples = get_samples(&f);
|
f.samples = ast_codec_get_samples(&f);
|
||||||
else
|
else
|
||||||
f.samples = 0;
|
f.samples = 0;
|
||||||
fr.outoforder = 0;
|
fr.outoforder = 0;
|
||||||
@@ -7355,7 +7313,7 @@ retryowner2:
|
|||||||
f.mallocd = 0;
|
f.mallocd = 0;
|
||||||
f.offset = 0;
|
f.offset = 0;
|
||||||
if (f.datalen && (f.frametype == AST_FRAME_VOICE)) {
|
if (f.datalen && (f.frametype == AST_FRAME_VOICE)) {
|
||||||
f.samples = get_samples(&f);
|
f.samples = ast_codec_get_samples(&f);
|
||||||
/* We need to byteswap incoming slinear samples from network byte order */
|
/* We need to byteswap incoming slinear samples from network byte order */
|
||||||
if (f.subclass == AST_FORMAT_SLINEAR)
|
if (f.subclass == AST_FORMAT_SLINEAR)
|
||||||
ast_frame_byteswap_be(&f);
|
ast_frame_byteswap_be(&f);
|
||||||
|
192
frame.c
192
frame.c
@@ -35,6 +35,12 @@ AST_MUTEX_DEFINE_STATIC(framelock);
|
|||||||
|
|
||||||
#define SMOOTHER_SIZE 8000
|
#define SMOOTHER_SIZE 8000
|
||||||
|
|
||||||
|
#define TYPE_HIGH 0x0
|
||||||
|
#define TYPE_LOW 0x1
|
||||||
|
#define TYPE_SILENCE 0x2
|
||||||
|
#define TYPE_DONTSEND 0x3
|
||||||
|
#define TYPE_MASK 0x3
|
||||||
|
|
||||||
struct ast_format_list {
|
struct ast_format_list {
|
||||||
int visible; /* Can we see this entry */
|
int visible; /* Can we see this entry */
|
||||||
int bits; /* bitmask value */
|
int bits; /* bitmask value */
|
||||||
@@ -1008,4 +1014,190 @@ void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, char *list
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int g723_len(unsigned char buf)
|
||||||
|
{
|
||||||
|
switch(buf & TYPE_MASK) {
|
||||||
|
case TYPE_DONTSEND:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case TYPE_SILENCE:
|
||||||
|
return 4;
|
||||||
|
break;
|
||||||
|
case TYPE_HIGH:
|
||||||
|
return 24;
|
||||||
|
break;
|
||||||
|
case TYPE_LOW:
|
||||||
|
return 20;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", buf & TYPE_MASK);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int g723_samples(unsigned char *buf, int maxlen)
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
int samples = 0;
|
||||||
|
int res;
|
||||||
|
while(pos < maxlen) {
|
||||||
|
res = g723_len(buf[pos]);
|
||||||
|
if (res <= 0)
|
||||||
|
break;
|
||||||
|
samples += 240;
|
||||||
|
pos += res;
|
||||||
|
}
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return off - bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int speex_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;
|
||||||
|
|
||||||
|
while ((len * 8 - bit) >= 5) {
|
||||||
|
/* skip wideband frames */
|
||||||
|
off = speex_get_wb_sz_at(data, len, bit);
|
||||||
|
if (off < 0) {
|
||||||
|
ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bit += off;
|
||||||
|
|
||||||
|
if ((len * 8 - bit) < 5) {
|
||||||
|
ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get control bits */
|
||||||
|
c = get_n_bits_at(data, 5, bit);
|
||||||
|
bit += 5;
|
||||||
|
|
||||||
|
if (c == 15) {
|
||||||
|
/* terminator */
|
||||||
|
break;
|
||||||
|
} else if (c == 14) {
|
||||||
|
/* in-band signal; next 4 bits contain signal id */
|
||||||
|
c = get_n_bits_at(data, 4, bit);
|
||||||
|
bit += 4;
|
||||||
|
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;
|
||||||
|
bit += c * 8;
|
||||||
|
} else if (c > 8) {
|
||||||
|
/* unknown */
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* skip number bits for submode (less the 5 control bits) */
|
||||||
|
bit += SpeexSubModeSz[c] - 5;
|
||||||
|
cnt += 160; /* new frame */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ast_codec_get_samples(struct ast_frame *f)
|
||||||
|
{
|
||||||
|
int samples=0;
|
||||||
|
switch(f->subclass) {
|
||||||
|
case AST_FORMAT_SPEEX:
|
||||||
|
samples = speex_samples(f->data, f->datalen);
|
||||||
|
break;
|
||||||
|
case AST_FORMAT_G723_1:
|
||||||
|
samples = g723_samples(f->data, f->datalen);
|
||||||
|
break;
|
||||||
|
case AST_FORMAT_ILBC:
|
||||||
|
samples = 240 * (f->datalen / 50);
|
||||||
|
break;
|
||||||
|
case AST_FORMAT_GSM:
|
||||||
|
samples = 160 * (f->datalen / 33);
|
||||||
|
break;
|
||||||
|
case AST_FORMAT_G729A:
|
||||||
|
samples = f->datalen * 8;
|
||||||
|
break;
|
||||||
|
case AST_FORMAT_SLINEAR:
|
||||||
|
samples = f->datalen / 2;
|
||||||
|
break;
|
||||||
|
case AST_FORMAT_LPC10:
|
||||||
|
/* assumes that the RTP packet contains one LPC10 frame */
|
||||||
|
samples = 22 * 8;
|
||||||
|
samples += (((char *)(f->data))[7] & 0x1) * 8;
|
||||||
|
break;
|
||||||
|
case AST_FORMAT_ULAW:
|
||||||
|
case AST_FORMAT_ALAW:
|
||||||
|
samples = f->datalen;
|
||||||
|
break;
|
||||||
|
case AST_FORMAT_ADPCM:
|
||||||
|
case AST_FORMAT_G726:
|
||||||
|
samples = f->datalen * 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
|
||||||
|
}
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -399,6 +399,9 @@ extern int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t
|
|||||||
/* Shift a codec preference list up or down 65 bytes so that it becomes an ASCII string */
|
/* Shift a codec preference list up or down 65 bytes so that it becomes an ASCII string */
|
||||||
extern void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right);
|
extern void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right);
|
||||||
|
|
||||||
|
/* Returns the number of samples contained in the frame */
|
||||||
|
extern int ast_codec_get_samples(struct ast_frame *f);
|
||||||
|
|
||||||
/* Gets duration in ms of interpolation frame for a format */
|
/* Gets duration in ms of interpolation frame for a format */
|
||||||
static inline int ast_codec_interp_len(int format)
|
static inline int ast_codec_interp_len(int format)
|
||||||
{
|
{
|
||||||
|
121
rtp.c
121
rtp.c
@@ -43,12 +43,6 @@
|
|||||||
|
|
||||||
#define RTP_MTU 1200
|
#define RTP_MTU 1200
|
||||||
|
|
||||||
#define TYPE_HIGH 0x0
|
|
||||||
#define TYPE_LOW 0x1
|
|
||||||
#define TYPE_SILENCE 0x2
|
|
||||||
#define TYPE_DONTSEND 0x3
|
|
||||||
#define TYPE_MASK 0x3
|
|
||||||
|
|
||||||
static int dtmftimeout = 3000; /* 3000 samples */
|
static int dtmftimeout = 3000; /* 3000 samples */
|
||||||
|
|
||||||
static int rtpstart = 0;
|
static int rtpstart = 0;
|
||||||
@@ -128,42 +122,6 @@ int ast_rtcp_fd(struct ast_rtp *rtp)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int g723_len(unsigned char buf)
|
|
||||||
{
|
|
||||||
switch(buf & TYPE_MASK) {
|
|
||||||
case TYPE_DONTSEND:
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
case TYPE_SILENCE:
|
|
||||||
return 4;
|
|
||||||
break;
|
|
||||||
case TYPE_HIGH:
|
|
||||||
return 24;
|
|
||||||
break;
|
|
||||||
case TYPE_LOW:
|
|
||||||
return 20;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", buf & TYPE_MASK);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int g723_samples(unsigned char *buf, int maxlen)
|
|
||||||
{
|
|
||||||
int pos = 0;
|
|
||||||
int samples = 0;
|
|
||||||
int res;
|
|
||||||
while(pos < maxlen) {
|
|
||||||
res = g723_len(buf[pos]);
|
|
||||||
if (res <= 0)
|
|
||||||
break;
|
|
||||||
samples += 240;
|
|
||||||
pos += res;
|
|
||||||
}
|
|
||||||
return samples;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ast_rtp_set_data(struct ast_rtp *rtp, void *data)
|
void ast_rtp_set_data(struct ast_rtp *rtp, void *data)
|
||||||
{
|
{
|
||||||
rtp->data = data;
|
rtp->data = data;
|
||||||
@@ -594,43 +552,9 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
|||||||
rtp->f.data = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
|
rtp->f.data = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
|
||||||
rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
|
rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
|
||||||
if (rtp->f.subclass < AST_FORMAT_MAX_AUDIO) {
|
if (rtp->f.subclass < AST_FORMAT_MAX_AUDIO) {
|
||||||
switch(rtp->f.subclass) {
|
rtp->f.samples = ast_codec_get_samples(&rtp->f);
|
||||||
case AST_FORMAT_ULAW:
|
if (rtp->f.subclass == AST_FORMAT_SLINEAR)
|
||||||
case AST_FORMAT_ALAW:
|
|
||||||
rtp->f.samples = rtp->f.datalen;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_SLINEAR:
|
|
||||||
rtp->f.samples = rtp->f.datalen / 2;
|
|
||||||
ast_frame_byteswap_be(&rtp->f);
|
ast_frame_byteswap_be(&rtp->f);
|
||||||
break;
|
|
||||||
case AST_FORMAT_GSM:
|
|
||||||
rtp->f.samples = 160 * (rtp->f.datalen / 33);
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_ILBC:
|
|
||||||
rtp->f.samples = 240 * (rtp->f.datalen / 50);
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_ADPCM:
|
|
||||||
case AST_FORMAT_G726:
|
|
||||||
rtp->f.samples = rtp->f.datalen * 2;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_G729A:
|
|
||||||
rtp->f.samples = rtp->f.datalen * 8;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_G723_1:
|
|
||||||
rtp->f.samples = g723_samples(rtp->f.data, rtp->f.datalen);
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_SPEEX:
|
|
||||||
/* assumes that the RTP packet contained one Speex frame */
|
|
||||||
rtp->f.samples = 160;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_LPC10:
|
|
||||||
rtp->f.samples = 22 * 8;
|
|
||||||
rtp->f.samples += (((char *)(rtp->f.data))[7] & 0x1) * 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ast_log(LOG_NOTICE, "Unable to calculate samples for format %s\n", ast_getformatname(rtp->f.subclass));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
|
calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
|
||||||
} else {
|
} else {
|
||||||
/* Video -- samples is # of samples vs. 90000 */
|
/* Video -- samples is # of samples vs. 90000 */
|
||||||
@@ -1233,45 +1157,8 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
|
|||||||
ms = calc_txstamp(rtp, &f->delivery);
|
ms = calc_txstamp(rtp, &f->delivery);
|
||||||
/* Default prediction */
|
/* Default prediction */
|
||||||
if (f->subclass < AST_FORMAT_MAX_AUDIO) {
|
if (f->subclass < AST_FORMAT_MAX_AUDIO) {
|
||||||
pred = rtp->lastts + ms * 8;
|
pred = rtp->lastts + ast_codec_get_samples(f);
|
||||||
|
|
||||||
switch(f->subclass) {
|
|
||||||
case AST_FORMAT_ULAW:
|
|
||||||
case AST_FORMAT_ALAW:
|
|
||||||
/* If we're within +/- 20ms from when where we
|
|
||||||
predict we should be, use that */
|
|
||||||
pred = rtp->lastts + f->datalen;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_ADPCM:
|
|
||||||
case AST_FORMAT_G726:
|
|
||||||
/* If we're within +/- 20ms from when where we
|
|
||||||
predict we should be, use that */
|
|
||||||
pred = rtp->lastts + f->datalen * 2;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_G729A:
|
|
||||||
pred = rtp->lastts + f->datalen * 8;
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_GSM:
|
|
||||||
pred = rtp->lastts + (f->datalen * 160 / 33);
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_ILBC:
|
|
||||||
pred = rtp->lastts + (f->datalen * 240 / 50);
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_G723_1:
|
|
||||||
pred = rtp->lastts + g723_samples(f->data, f->datalen);
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_SPEEX:
|
|
||||||
pred = rtp->lastts + 160;
|
|
||||||
/* assumes that the RTP packet contains one Speex frame */
|
|
||||||
break;
|
|
||||||
case AST_FORMAT_LPC10:
|
|
||||||
/* assumes that the RTP packet contains one LPC10 frame */
|
|
||||||
pred = rtp->lastts + 22 * 8;
|
|
||||||
pred += (((char *)(f->data))[7] & 0x1) * 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ast_log(LOG_WARNING, "Not sure about timestamp format for codec format %s\n", ast_getformatname(f->subclass));
|
|
||||||
}
|
|
||||||
/* Re-calculate last TS */
|
/* Re-calculate last TS */
|
||||||
rtp->lastts = rtp->lastts + ms * 8;
|
rtp->lastts = rtp->lastts + ms * 8;
|
||||||
if (!f->delivery.tv_sec && !f->delivery.tv_usec) {
|
if (!f->delivery.tv_sec && !f->delivery.tv_usec) {
|
||||||
|
Reference in New Issue
Block a user