From b96ae79baacf4012d524638c34f5eea97be426e5 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sun, 3 Apr 2005 22:57:18 +0000 Subject: 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 --- channels/chan_iax2.c | 7 +++++-- channels/chan_phone.c | 21 ++++++++++++++++----- channels/iax2-parser.c | 9 ++++++++- frame.c | 17 +++++++++++++++-- include/asterisk/frame.h | 23 ++++++++++++++++++++++- rtp.c | 14 ++++++++++++++ 6 files changed, 80 insertions(+), 11 deletions(-) diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 6135ca4a1..6ea03392d 100755 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -7337,9 +7337,12 @@ retryowner2: f.src = "IAX2"; f.mallocd = 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); - 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; iax_frame_wrap(&fr, &f); diff --git a/channels/chan_phone.c b/channels/chan_phone.c index 5cee02e6f..8e5bdb523 100755 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -544,10 +544,13 @@ static struct ast_frame *phone_read(struct ast_channel *ast) : AST_FRAME_VIDEO; p->fr.subclass = p->lastinput; 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; } -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; /* 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 */ if (space < len) 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; while(p->obuflen > 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) { 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; } @@ -729,12 +735,17 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame) memset(tmpbuf + 4, 0, sizeof(tmpbuf) - 4); memcpy(tmpbuf, frame->data, 4); expected = 24; - res = phone_write_buf(p, tmpbuf, expected, maxfr); + res = phone_write_buf(p, tmpbuf, expected, maxfr, 0); } res = 4; expected=4; } 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 ((errno != EAGAIN) && (errno != EINTR)) { diff --git a/channels/iax2-parser.c b/channels/iax2-parser.c index 3472b5008..f83e7413f 100755 --- a/channels/iax2-parser.c +++ b/channels/iax2-parser.c @@ -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_usec = 0; 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); + } } struct iax_frame *iax_frame_new(int direction, int datalen) diff --git a/frame.c b/frame.c index 673e7b46d..6ae728e9c 100755 --- a/frame.c +++ b/frame.c @@ -83,7 +83,7 @@ void ast_smoother_set_flags(struct ast_smoother *s, int 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) { 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; } } - 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 (!s->len || (!f->delivery.tv_sec && !f->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); } +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>8); +} + static struct ast_format_list AST_FORMAT_LIST[] = { { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"}, { 1, AST_FORMAT_GSM, "gsm" , "GSM"}, diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 2edf248a3..88eb6d5c7 100755 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -301,6 +301,19 @@ int ast_fr_fdwrite(int fd, struct ast_frame *frame); */ 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 */ /*! * \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 void ast_smoother_free(struct ast_smoother *s); 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); +#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); diff --git a/rtp.c b/rtp.c index cfcfc1c3d..22840eb3c 100755 --- a/rtp.c +++ b/rtp.c @@ -596,6 +596,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp) break; case AST_FORMAT_SLINEAR: rtp->f.samples = rtp->f.datalen / 2; + ast_frame_byteswap_be(&rtp->f); break; case AST_FORMAT_GSM: 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) { + 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_ALAW: if (!rtp->smoother) { -- cgit v1.2.3