]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
handle AST_FORMAT_SLINEAR endianness properly on big-endian systems (bug #3865)
authorRussell Bryant <russell@russellbryant.com>
Tue, 5 Apr 2005 07:10:06 +0000 (07:10 +0000)
committerRussell Bryant <russell@russellbryant.com>
Tue, 5 Apr 2005 07:10:06 +0000 (07:10 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5399 65c4cc65-6c06-0410-ace0-fbb531ad65f3

CHANGES
channels/chan_iax2.c
channels/chan_phone.c
channels/iax2-parser.c
frame.c
include/asterisk/frame.h
rtp.c

diff --git a/CHANGES b/CHANGES
index 9eb6965734c709858934e13f54f78489afc1fc9e..ffbb657d29010bb2c9d28a6694e287d586bd84ae 100755 (executable)
--- a/CHANGES
+++ b/CHANGES
@@ -27,6 +27,8 @@
        a new line, it would not be processed
     -- Fixed the logger so that color escape sequences wouldn't be sent to the logs
     -- Fixed a logic error when setting the "rtpchecksums" option
+    -- A lot of changes were made to correctly handle signed linear format on
+       big endian machines
 
 Asterisk 1.0.7
 
index 5d5315dabf7f9e32f68acc3d01c5c0db26993280..a6d87e6192b43ce4ab5036d2d850e3f60d3ca028 100755 (executable)
@@ -6034,9 +6034,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);
 
index d817776e75456da95e3a017dfa04e61641ca0a37..8b9b0db2ba3f55926361a2e415ed9e3f5b4db447 100755 (executable)
@@ -472,10 +472,13 @@ static struct ast_frame  *phone_read(struct ast_channel *ast)
        p->fr.frametype = AST_FRAME_VOICE;
        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, char *buf, int len, int frlen)
+static int phone_write_buf(struct phone_pvt *p, char *buf, int len, int frlen, int swap)
 {
        int res;
        /* Store as much of the buffer as we can, then write fixed frames */
@@ -483,7 +486,10 @@ static int phone_write_buf(struct phone_pvt *p, char *buf, int len, int frlen)
        /* 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);
@@ -628,12 +634,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)) {
index 34f251fb04df2e93a744df7772ec51f876d523c3..75f022d42a2c2f4ae0793aed14d734041487b406 100755 (executable)
@@ -688,8 +688,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 1b703c9d584ef80ccdf89fb886140654191543ce..1f2b8b1628413283c03c252e4d3b0b9413bda1c2 100755 (executable)
--- 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_memcpy_byteswap(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_memcpy_byteswap(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[] = {
        { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"},
        { 1, AST_FORMAT_GSM, "gsm" , "GSM"},
index c97973226af5fb2545a5cc3376f505fe20138672..2c0a91c13b2674e2dff0c19a512cd1b52edc1ef6 100755 (executable)
@@ -329,6 +329,18 @@ int ast_fr_fdwrite(int fd, struct ast_frame *frame);
  */
 int ast_fr_fdhangup(int fd);
 
+void ast_memcpy_byteswap(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_memcpy_byteswap(__f->data, __f->data, __f->samples); } while(0)
+#else
+#define ast_frame_byteswap_le(fr) do { struct ast_frame *__f = (fr); ast_memcpy_byteswap(__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
@@ -375,8 +387,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 35941edfd4ccb9cfaf808e47482c28f7f2c10292..04bedfe754c95b8c5a5e13aff8edba0bf5fa0f11 100755 (executable)
--- a/rtp.c
+++ b/rtp.c
@@ -547,6 +547,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);
@@ -1196,6 +1197,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) {