mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 04:30:28 +00:00
handle AST_FORMAT_SLINEAR endianness properly on big-endian systems (bug #3865)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5373 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -7337,9 +7337,12 @@ retryowner2:
|
|||||||
f.src = "IAX2";
|
f.src = "IAX2";
|
||||||
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 = get_samples(&f);
|
||||||
else
|
/* We need to byteswap incoming slinear samples from network byte order */
|
||||||
|
if (f.subclass == AST_FORMAT_SLINEAR)
|
||||||
|
ast_frame_byteswap_be(&f);
|
||||||
|
} else
|
||||||
f.samples = 0;
|
f.samples = 0;
|
||||||
iax_frame_wrap(&fr, &f);
|
iax_frame_wrap(&fr, &f);
|
||||||
|
|
||||||
|
@@ -544,10 +544,13 @@ static struct ast_frame *phone_read(struct ast_channel *ast)
|
|||||||
: AST_FRAME_VIDEO;
|
: AST_FRAME_VIDEO;
|
||||||
p->fr.subclass = p->lastinput;
|
p->fr.subclass = p->lastinput;
|
||||||
p->fr.offset = AST_FRIENDLY_OFFSET;
|
p->fr.offset = AST_FRIENDLY_OFFSET;
|
||||||
|
/* Byteswap from little-endian to native-endian */
|
||||||
|
if (p->fr.subclass == AST_FORMAT_SLINEAR)
|
||||||
|
ast_frame_byteswap_le(&p->fr);
|
||||||
return &p->fr;
|
return &p->fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int frlen)
|
static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int frlen, int swap)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
/* Store as much of the buffer as we can, then write fixed frames */
|
/* Store as much of the buffer as we can, then write fixed frames */
|
||||||
@@ -555,7 +558,10 @@ static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int fr
|
|||||||
/* Make sure we have enough buffer space to store the frame */
|
/* Make sure we have enough buffer space to store the frame */
|
||||||
if (space < len)
|
if (space < len)
|
||||||
len = space;
|
len = space;
|
||||||
memcpy(p->obuf + p->obuflen, buf, len);
|
if (swap)
|
||||||
|
ast_memcpy_byteswap(p->obuf+p->obuflen, buf, len/2);
|
||||||
|
else
|
||||||
|
memcpy(p->obuf + p->obuflen, buf, len);
|
||||||
p->obuflen += len;
|
p->obuflen += len;
|
||||||
while(p->obuflen > frlen) {
|
while(p->obuflen > frlen) {
|
||||||
res = write(p->fd, p->obuf, frlen);
|
res = write(p->fd, p->obuf, frlen);
|
||||||
@@ -581,7 +587,7 @@ static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int fr
|
|||||||
static int phone_send_text(struct ast_channel *ast, const char *text)
|
static int phone_send_text(struct ast_channel *ast, const char *text)
|
||||||
{
|
{
|
||||||
int length = strlen(text);
|
int length = strlen(text);
|
||||||
return phone_write_buf(ast->tech_pvt, text, length, length) ==
|
return phone_write_buf(ast->tech_pvt, text, length, length, 0) ==
|
||||||
length ? 0 : -1;
|
length ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -729,12 +735,17 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
|
|||||||
memset(tmpbuf + 4, 0, sizeof(tmpbuf) - 4);
|
memset(tmpbuf + 4, 0, sizeof(tmpbuf) - 4);
|
||||||
memcpy(tmpbuf, frame->data, 4);
|
memcpy(tmpbuf, frame->data, 4);
|
||||||
expected = 24;
|
expected = 24;
|
||||||
res = phone_write_buf(p, tmpbuf, expected, maxfr);
|
res = phone_write_buf(p, tmpbuf, expected, maxfr, 0);
|
||||||
}
|
}
|
||||||
res = 4;
|
res = 4;
|
||||||
expected=4;
|
expected=4;
|
||||||
} else {
|
} else {
|
||||||
res = phone_write_buf(p, pos, expected, maxfr);
|
int swap = 0;
|
||||||
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
if (frame->subclass == AST_FORMAT_SLINEAR)
|
||||||
|
swap = 1; /* Swap big-endian samples to little-endian as we copy */
|
||||||
|
#endif
|
||||||
|
res = phone_write_buf(p, pos, expected, maxfr, swap);
|
||||||
}
|
}
|
||||||
if (res != expected) {
|
if (res != expected) {
|
||||||
if ((errno != EAGAIN) && (errno != EINTR)) {
|
if ((errno != EAGAIN) && (errno != EINTR)) {
|
||||||
|
@@ -855,8 +855,15 @@ void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
|
|||||||
fr->af.delivery.tv_sec = 0;
|
fr->af.delivery.tv_sec = 0;
|
||||||
fr->af.delivery.tv_usec = 0;
|
fr->af.delivery.tv_usec = 0;
|
||||||
fr->af.data = fr->afdata;
|
fr->af.data = fr->afdata;
|
||||||
if (fr->af.datalen)
|
if (fr->af.datalen) {
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
/* We need to byte-swap slinear samples from network byte order */
|
||||||
|
if (fr->af.subclass == AST_FORMAT_SLINEAR) {
|
||||||
|
ast_memcpy_byteswap(fr->af.data, f->data, fr->af.samples);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
memcpy(fr->af.data, f->data, fr->af.datalen);
|
memcpy(fr->af.data, f->data, fr->af.datalen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iax_frame *iax_frame_new(int direction, int datalen)
|
struct iax_frame *iax_frame_new(int direction, int datalen)
|
||||||
|
17
frame.c
17
frame.c
@@ -83,7 +83,7 @@ void ast_smoother_set_flags(struct ast_smoother *s, int flags)
|
|||||||
s->flags = flags;
|
s->flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
|
int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
|
||||||
{
|
{
|
||||||
if (f->frametype != AST_FRAME_VOICE) {
|
if (f->frametype != AST_FRAME_VOICE) {
|
||||||
ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
|
ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n");
|
||||||
@@ -129,7 +129,10 @@ int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memcpy(s->data + s->len, f->data, f->datalen);
|
if (swap)
|
||||||
|
ast_swapcopy_samples(s->data+s->len, f->data, f->samples);
|
||||||
|
else
|
||||||
|
memcpy(s->data + s->len, f->data, f->datalen);
|
||||||
/* If either side is empty, reset the delivery time */
|
/* If either side is empty, reset the delivery time */
|
||||||
if (!s->len || (!f->delivery.tv_sec && !f->delivery.tv_usec) ||
|
if (!s->len || (!f->delivery.tv_sec && !f->delivery.tv_usec) ||
|
||||||
(!s->delivery.tv_sec && !s->delivery.tv_usec))
|
(!s->delivery.tv_sec && !s->delivery.tv_usec))
|
||||||
@@ -399,6 +402,16 @@ int ast_fr_fdhangup(int fd)
|
|||||||
return ast_fr_fdwrite(fd, &hangup);
|
return ast_fr_fdwrite(fd, &hangup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ast_swapcopy_samples(void *dst, void *src, int samples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned short *dst_s = dst;
|
||||||
|
unsigned short *src_s = src;
|
||||||
|
|
||||||
|
for (i=0; i<samples; i++)
|
||||||
|
dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8);
|
||||||
|
}
|
||||||
|
|
||||||
static struct ast_format_list AST_FORMAT_LIST[] = {
|
static struct ast_format_list AST_FORMAT_LIST[] = {
|
||||||
{ 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"},
|
{ 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"},
|
||||||
{ 1, AST_FORMAT_GSM, "gsm" , "GSM"},
|
{ 1, AST_FORMAT_GSM, "gsm" , "GSM"},
|
||||||
|
@@ -301,6 +301,19 @@ int ast_fr_fdwrite(int fd, struct ast_frame *frame);
|
|||||||
*/
|
*/
|
||||||
int ast_fr_fdhangup(int fd);
|
int ast_fr_fdhangup(int fd);
|
||||||
|
|
||||||
|
void ast_swapcopy_samples(void *dst, void *src, int samples);
|
||||||
|
|
||||||
|
/* Helpers for byteswapping native samples to/from
|
||||||
|
little-endian and big-endian. */
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
#define ast_frame_byteswap_le(fr) do { ; } while(0)
|
||||||
|
#define ast_frame_byteswap_be(fr) do { struct ast_frame *__f = (fr); ast_swapcopy_samples(__f->data, __f->data, __f->samples); } while(0)
|
||||||
|
#else
|
||||||
|
#define ast_frame_byteswap_le(fr) do { struct ast_frame *__f = (fr); ast_swapcopy_samples(__f->data, __f->data, __f->samples); } while(0)
|
||||||
|
#define ast_frame_byteswap_be(fr) do { ; } while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*! Get the name of a format */
|
/*! Get the name of a format */
|
||||||
/*!
|
/*!
|
||||||
* \param format id of format
|
* \param format id of format
|
||||||
@@ -347,8 +360,16 @@ extern void ast_smoother_set_flags(struct ast_smoother *smoother, int flags);
|
|||||||
extern int ast_smoother_get_flags(struct ast_smoother *smoother);
|
extern int ast_smoother_get_flags(struct ast_smoother *smoother);
|
||||||
extern void ast_smoother_free(struct ast_smoother *s);
|
extern void ast_smoother_free(struct ast_smoother *s);
|
||||||
extern void ast_smoother_reset(struct ast_smoother *s, int bytes);
|
extern void ast_smoother_reset(struct ast_smoother *s, int bytes);
|
||||||
extern int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f);
|
extern int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap);
|
||||||
extern struct ast_frame *ast_smoother_read(struct ast_smoother *s);
|
extern struct ast_frame *ast_smoother_read(struct ast_smoother *s);
|
||||||
|
#define ast_smoother_feed(s,f) do { __ast_smoother_feed(s, f, 0); } while(0)
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
#define ast_smoother_feed_be(s,f) do { __ast_smoother_feed(s, f, 1); } while(0)
|
||||||
|
#define ast_smoother_feed_le(s,f) do { __ast_smoother_feed(s, f, 0); } while(0)
|
||||||
|
#else
|
||||||
|
#define ast_smoother_feed_be(s,f) do { __ast_smoother_feed(s, f, 0); } while(0)
|
||||||
|
#define ast_smoother_feed_le(s,f) do { __ast_smoother_feed(s, f, 1); } while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
extern void ast_frame_dump(char *name, struct ast_frame *f, char *prefix);
|
extern void ast_frame_dump(char *name, struct ast_frame *f, char *prefix);
|
||||||
|
|
||||||
|
14
rtp.c
14
rtp.c
@@ -596,6 +596,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
|||||||
break;
|
break;
|
||||||
case AST_FORMAT_SLINEAR:
|
case AST_FORMAT_SLINEAR:
|
||||||
rtp->f.samples = rtp->f.datalen / 2;
|
rtp->f.samples = rtp->f.datalen / 2;
|
||||||
|
ast_frame_byteswap_be(&rtp->f);
|
||||||
break;
|
break;
|
||||||
case AST_FORMAT_GSM:
|
case AST_FORMAT_GSM:
|
||||||
rtp->f.samples = 160 * (rtp->f.datalen / 33);
|
rtp->f.samples = 160 * (rtp->f.datalen / 33);
|
||||||
@@ -1320,6 +1321,19 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
|
|||||||
|
|
||||||
|
|
||||||
switch(subclass) {
|
switch(subclass) {
|
||||||
|
case AST_FORMAT_SLINEAR:
|
||||||
|
if (!rtp->smoother) {
|
||||||
|
rtp->smoother = ast_smoother_new(320);
|
||||||
|
}
|
||||||
|
if (!rtp->smoother) {
|
||||||
|
ast_log(LOG_WARNING, "Unable to create smoother :(\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ast_smoother_feed_be(rtp->smoother, _f);
|
||||||
|
|
||||||
|
while((f = ast_smoother_read(rtp->smoother)))
|
||||||
|
ast_rtp_raw_write(rtp, f, codec);
|
||||||
|
break;
|
||||||
case AST_FORMAT_ULAW:
|
case AST_FORMAT_ULAW:
|
||||||
case AST_FORMAT_ALAW:
|
case AST_FORMAT_ALAW:
|
||||||
if (!rtp->smoother) {
|
if (!rtp->smoother) {
|
||||||
|
Reference in New Issue
Block a user