Handle binding more nicely
[asterisk/asterisk.git] / rtp.c
diff --git a/rtp.c b/rtp.c
index a60e9d5..cb2dd20 100755 (executable)
--- a/rtp.c
+++ b/rtp.c
@@ -31,6 +31,7 @@
 #include <asterisk/options.h>
 #include <asterisk/channel.h>
 #include <asterisk/acl.h>
+#include <asterisk/channel.h>
 #include <asterisk/channel_pvt.h>
 #include <asterisk/config.h>
 
@@ -42,7 +43,7 @@
 #define TYPE_DONTSEND   0x3
 #define TYPE_MASK       0x3
 
-static int dtmftimeout = 300;  /* 300 samples */
+static int dtmftimeout = 3000; /* 3000 samples */
 
 static int rtpstart = 0;
 static int rtpend = 0;
@@ -55,6 +56,8 @@ struct rtpPayloadType {
 
 #define MAX_RTP_PT 256
 
+#define FLAG_3389_WARNING (1 << 0)
+
 struct ast_rtp {
        int s;
        char resp;
@@ -65,14 +68,18 @@ struct ast_rtp {
        unsigned int lastrxts;
        unsigned int lastividtimestamp;
        unsigned int lastovidtimestamp;
+       unsigned int lasteventseqn;
        int lasttxformat;
        int lastrxformat;
        int dtmfcount;
+       unsigned int dtmfduration;
        int nat;
+       int flags;
        struct sockaddr_in us;
        struct sockaddr_in them;
        struct timeval rxcore;
        struct timeval txcore;
+       struct timeval dtmfmute;
        struct ast_smoother *smoother;
        int *ioid;
        unsigned short seqno;
@@ -136,7 +143,7 @@ static int g723_samples(unsigned char *buf, int maxlen)
        int res;
        while(pos < maxlen) {
                res = g723_len(buf[pos]);
-               if (res < 0)
+               if (res <= 0)
                        break;
                samples += 240;
                pos += res;
@@ -161,7 +168,17 @@ void ast_rtp_setnat(struct ast_rtp *rtp, int nat)
 
 static struct ast_frame *send_dtmf(struct ast_rtp *rtp)
 {
-       ast_log(LOG_DEBUG, "Sending dtmf: %d (%c)\n", rtp->resp, rtp->resp);
+       struct timeval tv;
+       static struct ast_frame null_frame = { AST_FRAME_NULL, };
+       gettimeofday(&tv, NULL);
+       if ((tv.tv_sec < rtp->dtmfmute.tv_sec) ||
+           ((tv.tv_sec == rtp->dtmfmute.tv_sec) && (tv.tv_usec < rtp->dtmfmute.tv_usec))) {
+               ast_log(LOG_DEBUG, "Ignore potential DTMF echo from '%s'\n", inet_ntoa(rtp->them.sin_addr));
+               rtp->resp = 0;
+               rtp->dtmfduration = 0;
+               return &null_frame;
+       }
+       ast_log(LOG_DEBUG, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, inet_ntoa(rtp->them.sin_addr));
        rtp->f.frametype = AST_FRAME_DTMF;
        rtp->f.subclass = rtp->resp;
        rtp->f.datalen = 0;
@@ -169,6 +186,7 @@ static struct ast_frame *send_dtmf(struct ast_rtp *rtp)
        rtp->f.mallocd = 0;
        rtp->f.src = "RTP";
        rtp->resp = 0;
+       rtp->dtmfduration = 0;
        return &rtp->f;
        
 }
@@ -203,10 +221,17 @@ static struct ast_frame *process_cisco_dtmf(struct ast_rtp *rtp, unsigned char *
 static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *data, int len)
 {
        unsigned int event;
+       unsigned int event_end;
+       unsigned int duration;
        char resp = 0;
        struct ast_frame *f = NULL;
        event = ntohl(*((unsigned int *)(data)));
        event >>= 24;
+       event_end = ntohl(*((unsigned int *)(data)));
+       event_end <<= 8;
+       event_end >>= 24;
+       duration = ntohl(*((unsigned int *)(data)));
+       duration &= 0xFFFF;
 #if 0
        printf("Event: %08x (len = %d)\n", event, len);
 #endif 
@@ -222,8 +247,23 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat
        if (rtp->resp && (rtp->resp != resp)) {
                f = send_dtmf(rtp);
        }
-       rtp->resp = resp;
+       else if(event_end & 0x80)
+       {
+               if (rtp->resp) {
+                       f = send_dtmf(rtp);
+                       rtp->resp = 0;
+               }
+               resp = 0;
+               duration = 0;
+       }
+       else if(rtp->dtmfduration && (duration < rtp->dtmfduration))
+       {
+               f = send_dtmf(rtp);
+       }
+       if (!(event_end & 0x80))
+               rtp->resp = resp;
        rtp->dtmfcount = dtmftimeout;
+       rtp->dtmfduration = duration;
        return f;
 }
 
@@ -236,7 +276,10 @@ static struct ast_frame *process_rfc3389(struct ast_rtp *rtp, unsigned char *dat
 #if 0
        printf("RFC3389: %d bytes, format is %d\n", len, rtp->lastrxformat);
 #endif 
-       ast_log(LOG_NOTICE, "RFC3389 support incomplete.  Turn off on client if possible\n");
+       if (!(rtp->flags & FLAG_3389_WARNING)) {
+               ast_log(LOG_NOTICE, "RFC3389 support incomplete.  Turn off on client if possible\n");
+               rtp->flags |= FLAG_3389_WARNING;
+       }
        if (!rtp->lastrxformat)
                return  NULL;
        switch(rtp->lastrxformat) {
@@ -319,10 +362,32 @@ struct ast_frame *ast_rtcp_read(struct ast_rtp *rtp)
                        ast_log(LOG_DEBUG, "RTP NAT: Using address %s:%d\n", inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
                }
        }
-       ast_log(LOG_DEBUG, "Got RTCP report of %d bytes\n", res);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Got RTCP report of %d bytes\n", res);
        return &null_frame;
 }
 
+static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int timestamp, int mark)
+{
+       if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) {
+               gettimeofday(&rtp->rxcore, NULL);
+               rtp->rxcore.tv_sec -= timestamp / 8000;
+               rtp->rxcore.tv_usec -= (timestamp % 8000) * 125;
+               rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 20000;
+               if (rtp->rxcore.tv_usec < 0) {
+                       /* Adjust appropriately if necessary */
+                       rtp->rxcore.tv_usec += 1000000;
+                       rtp->rxcore.tv_sec -= 1;
+               }
+       }
+       tv->tv_sec = rtp->rxcore.tv_sec + timestamp / 8000;
+       tv->tv_usec = rtp->rxcore.tv_usec + (timestamp % 8000) * 125;
+       if (tv->tv_usec >= 1000000) {
+               tv->tv_usec -= 1000000;
+               tv->tv_sec += 1;
+       }
+}
+
 struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
 {
        int res;
@@ -346,7 +411,10 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
 
        rtpheader = (unsigned int *)(rtp->rawdata + AST_FRIENDLY_OFFSET);
        if (res < 0) {
-               ast_log(LOG_WARNING, "RTP Read error: %s\n", strerror(errno));
+               if (errno == EAGAIN)
+                       ast_log(LOG_NOTICE, "RTP: Received packet with bad UDP checksum\n");
+               else
+                       ast_log(LOG_WARNING, "RTP Read error: %s\n", strerror(errno));
                if (errno == EBADF)
                        CRASH;
                return &null_frame;
@@ -355,6 +423,12 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
                ast_log(LOG_WARNING, "RTP Read too short\n");
                return &null_frame;
        }
+
+       /* Ignore if the other side hasn't been given an address
+          yet.  */
+       if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
+               return &null_frame;
+
        if (rtp->nat) {
                /* Send to whoever sent to us */
                if ((rtp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
@@ -363,6 +437,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
                        ast_log(LOG_DEBUG, "RTP NAT: Using address %s:%d\n", inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port));
                }
        }
+
        /* Get fields */
        seqno = ntohl(rtpheader[0]);
        payloadtype = (seqno & 0x7f0000) >> 16;
@@ -378,11 +453,17 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
          // This is special in-band data that's not one of our codecs
          if (rtpPT.code == AST_RTP_DTMF) {
            /* It's special -- rfc2833 process it */
-           f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
+           if (rtp->lasteventseqn <= seqno) {
+             f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
+             rtp->lasteventseqn = seqno;
+           }
            if (f) return f; else return &null_frame;
          } else if (rtpPT.code == AST_RTP_CISCO_DTMF) {
            /* It's really special -- process it the Cisco way */
-           f = process_cisco_dtmf(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
+           if (rtp->lasteventseqn <= seqno) {
+             f = process_cisco_dtmf(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
+             rtp->lasteventseqn = seqno;
+           }
            if (f) return f; else return &null_frame;
          } else if (rtpPT.code == AST_RTP_CN) {
            /* Comfort Noise */
@@ -442,6 +523,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
                        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:
@@ -455,13 +537,18 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
                        // assumes that the RTP packet contained one Speex frame
                        break;
                default:
-                       ast_log(LOG_NOTICE, "Unable to calculate samples for format %d\n", rtp->f.subclass);
+                       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);
        } else {
                /* Video -- samples is # of samples vs. 90000 */
+               if (!rtp->lastividtimestamp)
+                       rtp->lastividtimestamp = timestamp;
                rtp->f.samples = timestamp - rtp->lastividtimestamp;
                rtp->lastividtimestamp = timestamp;
+               rtp->f.delivery.tv_sec = 0;
+               rtp->f.delivery.tv_usec = 0;
                if (mark)
                        rtp->f.subclass |= 0x1;
                
@@ -481,7 +568,7 @@ static struct {
   {{1, AST_FORMAT_GSM}, "audio", "GSM"},
   {{1, AST_FORMAT_ULAW}, "audio", "PCMU"},
   {{1, AST_FORMAT_ALAW}, "audio", "PCMA"},
-  {{1, AST_FORMAT_MP3}, "audio", "MPA"},
+  {{1, AST_FORMAT_G726}, "audio", "G726-32"},
   {{1, AST_FORMAT_ADPCM}, "audio", "DVI4"},
   {{1, AST_FORMAT_SLINEAR}, "audio", "L16"},
   {{1, AST_FORMAT_LPC10}, "audio", "LPC"},
@@ -502,6 +589,7 @@ static struct {
    table for transmission */
 static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
   [0] = {1, AST_FORMAT_ULAW},
+  [2] = {1, AST_FORMAT_G726}, // Technically this is G.721, but if Cisco can do it, so can we...
   [3] = {1, AST_FORMAT_GSM},
   [4] = {1, AST_FORMAT_G723_1},
   [5] = {1, AST_FORMAT_ADPCM}, // 8 kHz
@@ -511,7 +599,6 @@ static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
   [10] = {1, AST_FORMAT_SLINEAR}, // 2 channels
   [11] = {1, AST_FORMAT_SLINEAR}, // 1 channel
   [13] = {0, AST_RTP_CN},
-  [14] = {1, AST_FORMAT_MP3},
   [16] = {1, AST_FORMAT_ADPCM}, // 11.025 kHz
   [17] = {1, AST_FORMAT_ADPCM}, // 22.050 kHz
   [18] = {1, AST_FORMAT_G729A},
@@ -596,14 +683,19 @@ void ast_rtp_get_current_formats(struct ast_rtp* rtp,
   }
 }
 
-struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt) {
+struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt) 
+{
+  struct rtpPayloadType result;
   if (pt < 0 || pt > MAX_RTP_PT) {
-    struct rtpPayloadType result;
     result.isAstFormat = result.code = 0;
     return result; // bogus payload type
   }
-  /* Gotta use our static one, since that's what we sent against */
-  return static_RTP_PT[pt];
+  /* Start with the negotiated codecs */
+  result = rtp->current_RTP_PT[pt];
+  /* If it doesn't exist, check our static RTP type list, just in case */
+  if (!result.code) 
+       result = static_RTP_PT[pt];
+  return result;
 }
 
 int ast_rtp_lookup_code(struct ast_rtp* rtp, int isAstFormat, int code) {
@@ -617,6 +709,18 @@ int ast_rtp_lookup_code(struct ast_rtp* rtp, int isAstFormat, int code) {
     return rtp->rtp_lookup_code_cache_result;
   }
 
+       /* Check the dynamic list first */
+  for (pt = 0; pt < MAX_RTP_PT; ++pt) {
+    if (rtp->current_RTP_PT[pt].code == code &&
+               rtp->current_RTP_PT[pt].isAstFormat == isAstFormat) {
+      rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
+      rtp->rtp_lookup_code_cache_code = code;
+      rtp->rtp_lookup_code_cache_result = pt;
+      return pt;
+    }
+  }
+
+       /* Then the static list */
   for (pt = 0; pt < MAX_RTP_PT; ++pt) {
     if (static_RTP_PT[pt].code == code &&
                static_RTP_PT[pt].isAstFormat == isAstFormat) {
@@ -641,23 +745,32 @@ char* ast_rtp_lookup_mime_subtype(int isAstFormat, int code) {
   return "";
 }
 
+static int rtp_socket(void)
+{
+       int s;
+       long flags;
+       s = socket(AF_INET, SOCK_DGRAM, 0);
+       if (s > -1) {
+               flags = fcntl(s, F_GETFL);
+               fcntl(s, F_SETFL, flags | O_NONBLOCK);
+       }
+       return s;
+}
+
 static struct ast_rtcp *ast_rtcp_new(void)
 {
        struct ast_rtcp *rtcp;
-       long flags;
        rtcp = malloc(sizeof(struct ast_rtcp));
        if (!rtcp)
                return NULL;
        memset(rtcp, 0, sizeof(struct ast_rtcp));
-       rtcp->s = socket(AF_INET, SOCK_DGRAM, 0);
+       rtcp->s = rtp_socket();
        rtcp->us.sin_family = AF_INET;
        if (rtcp->s < 0) {
                free(rtcp);
                ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
                return NULL;
        }
-       flags = fcntl(rtcp->s, F_GETFL);
-       fcntl(rtcp->s, F_SETFL, flags | O_NONBLOCK);
        return rtcp;
 }
 
@@ -665,7 +778,7 @@ struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io,
 {
        struct ast_rtp *rtp;
        int x;
-       int flags;
+       int first;
        int startplace;
        rtp = malloc(sizeof(struct ast_rtp));
        if (!rtp)
@@ -673,7 +786,7 @@ struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io,
        memset(rtp, 0, sizeof(struct ast_rtp));
        rtp->them.sin_family = AF_INET;
        rtp->us.sin_family = AF_INET;
-       rtp->s = socket(AF_INET, SOCK_DGRAM, 0);
+       rtp->s = rtp_socket();
        rtp->ssrc = rand();
        rtp->seqno = rand() & 0xffff;
        if (rtp->s < 0) {
@@ -685,8 +798,6 @@ struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io,
                rtp->sched = sched;
                rtp->rtcp = ast_rtcp_new();
        }
-       flags = fcntl(rtp->s, F_GETFL);
-       fcntl(rtp->s, F_SETFL, flags | O_NONBLOCK);
        /* Find us a place */
        x = (rand() % (rtpend-rtpstart)) + rtpstart;
        x = x & ~1;
@@ -696,9 +807,14 @@ struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io,
                rtp->us.sin_port = htons(x);
                if (rtp->rtcp)
                        rtp->rtcp->us.sin_port = htons(x + 1);
-               if (!bind(rtp->s, &rtp->us, sizeof(rtp->us)) &&
-                       (!rtp->rtcp || !bind(rtp->rtcp->s, &rtp->rtcp->us, sizeof(rtp->rtcp->us))))
+               if (!(first = bind(rtp->s, (struct sockaddr *)&rtp->us, sizeof(rtp->us))) &&
+                       (!rtp->rtcp || !bind(rtp->rtcp->s, (struct sockaddr *)&rtp->rtcp->us, sizeof(rtp->rtcp->us))))
                        break;
+               if (!first) {
+                       /* Primary bind succeeded! Gotta recreate it */
+                       close(rtp->s);
+                       rtp->s = rtp_socket();
+               }
                if (errno != EADDRINUSE) {
                        ast_log(LOG_WARNING, "Unexpected bind error: %s\n", strerror(errno));
                        close(rtp->s);
@@ -788,19 +904,28 @@ void ast_rtp_destroy(struct ast_rtp *rtp)
        free(rtp);
 }
 
-static unsigned int calc_txstamp(struct ast_rtp *rtp)
+static unsigned int calc_txstamp(struct ast_rtp *rtp, struct timeval *delivery)
 {
        struct timeval now;
        unsigned int ms;
        if (!rtp->txcore.tv_sec && !rtp->txcore.tv_usec) {
                gettimeofday(&rtp->txcore, NULL);
+               rtp->txcore.tv_usec -= rtp->txcore.tv_usec % 20000;
+       }
+       if (delivery && (delivery->tv_sec || delivery->tv_usec)) {
+               /* Use previous txcore */
+               ms = (delivery->tv_sec - rtp->txcore.tv_sec) * 1000;
+               ms += (delivery->tv_usec - rtp->txcore.tv_usec) / 1000;
+               rtp->txcore.tv_sec = delivery->tv_sec;
+               rtp->txcore.tv_usec = delivery->tv_usec;
+       } else {
+               gettimeofday(&now, NULL);
+               ms = (now.tv_sec - rtp->txcore.tv_sec) * 1000;
+               ms += (now.tv_usec - rtp->txcore.tv_usec) / 1000;
+               /* Use what we just got for next time */
+               rtp->txcore.tv_sec = now.tv_sec;
+               rtp->txcore.tv_usec = now.tv_usec;
        }
-       gettimeofday(&now, NULL);
-       ms = (now.tv_sec - rtp->txcore.tv_sec) * 1000;
-       ms += (now.tv_usec - rtp->txcore.tv_usec) / 1000;
-       /* Use what we just got for next time */
-       rtp->txcore.tv_sec = now.tv_sec;
-       rtp->txcore.tv_usec = now.tv_usec;
        return ms;
 }
 
@@ -810,7 +935,6 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
        int hdrlen = 12;
        int res;
        int ms;
-       int pred;
        int x;
        char data[256];
 
@@ -834,9 +958,16 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
        if (!rtp->them.sin_addr.s_addr)
                return 0;
 
-       ms = calc_txstamp(rtp);
+       gettimeofday(&rtp->dtmfmute, NULL);
+       rtp->dtmfmute.tv_usec += (500 * 1000);
+       if (rtp->dtmfmute.tv_usec > 1000000) {
+               rtp->dtmfmute.tv_usec -= 1000000;
+               rtp->dtmfmute.tv_sec += 1;
+       }
+
+       ms = calc_txstamp(rtp, NULL);
        /* Default prediction */
-       pred = rtp->lastts + ms * 8;
+       rtp->lastts = rtp->lastts + ms * 8;
        
        /* Get a pointer to the header */
        rtpheader = (unsigned int *)data;
@@ -846,7 +977,7 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
        rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
        for (x=0;x<4;x++) {
                if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
-                       res = sendto(rtp->s, (void *)rtpheader, hdrlen + 4, 0, &rtp->them, sizeof(rtp->them));
+                       res = sendto(rtp->s, (void *)rtpheader, hdrlen + 4, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
                        if (res <0) 
                                ast_log(LOG_NOTICE, "RTP Transmission error to %s:%d: %s\n", inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
        #if 0
@@ -856,8 +987,8 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
                if (x ==0) {
                        /* Clear marker bit and increment seqno */
                        rtpheader[0] = htonl((2 << 30)  | (101 << 16) | (rtp->seqno++));
-                       /* Make duration 240 */
-                       rtpheader[3] |= htonl((240));
+                       /* Make duration 800 (100ms) */
+                       rtpheader[3] |= htonl((800));
                        /* Set the End bit for the last 3 */
                        rtpheader[3] |= htonl((1 << 23));
                }
@@ -874,7 +1005,7 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
        int pred;
        int mark = 0;
 
-       ms = calc_txstamp(rtp);
+       ms = calc_txstamp(rtp, &f->delivery);
        /* Default prediction */
        if (f->subclass < AST_FORMAT_MAX_AUDIO) {
                pred = rtp->lastts + ms * 8;
@@ -886,6 +1017,12 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
                           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;
@@ -899,32 +1036,38 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
                        pred = rtp->lastts + g723_samples(f->data, f->datalen);
                        break;
                case AST_FORMAT_SPEEX:
-                       pred = rtp->lastts + 160;
+                   pred = rtp->lastts + 160;
                        // assumes that the RTP packet contains one Speex frame
                        break;
                default:
-                       ast_log(LOG_WARNING, "Not sure about timestamp format for codec format %d\n", f->subclass);
+                       ast_log(LOG_WARNING, "Not sure about timestamp format for codec format %s\n", ast_getformatname(f->subclass));
                }
-
                /* Re-calculate last TS */
                rtp->lastts = rtp->lastts + ms * 8;
-               /* If it's close to our prediction, go for it */
-               if (abs(rtp->lastts - pred) < 640)
-                       rtp->lastts = pred;
-               else
-                       ast_log(LOG_DEBUG, "Difference is %d, ms is %d\n", abs(rtp->lastts - pred), ms);
+               if (!f->delivery.tv_sec && !f->delivery.tv_usec) {
+                       /* If this isn't an absolute delivery time, Check if it is close to our prediction, 
+                          and if so, go with our prediction */
+                       if (abs(rtp->lastts - pred) < 640)
+                               rtp->lastts = pred;
+                       else {
+                               ast_log(LOG_DEBUG, "Difference is %d, ms is %d\n", abs(rtp->lastts - pred), ms);
+                               mark = 1;
+                       }
+               }
        } else {
                mark = f->subclass & 0x1;
                pred = rtp->lastovidtimestamp + f->samples;
                /* Re-calculate last TS */
                rtp->lastts = rtp->lastts + ms * 90;
                /* If it's close to our prediction, go for it */
-               if (abs(rtp->lastts - pred) < 7200) {
-                       rtp->lastts = pred;
-                       rtp->lastovidtimestamp += f->samples;
-               } else {
-                       ast_log(LOG_DEBUG, "Difference is %d, ms is %d\n", abs(rtp->lastts - pred), ms);
-                       rtp->lastovidtimestamp = rtp->lastts;
+               if (!f->delivery.tv_sec && !f->delivery.tv_usec) {
+                       if (abs(rtp->lastts - pred) < 7200) {
+                               rtp->lastts = pred;
+                               rtp->lastovidtimestamp += f->samples;
+                       } else {
+                               ast_log(LOG_DEBUG, "Difference is %d, ms is %d (%d), pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, f->samples);
+                               rtp->lastovidtimestamp = rtp->lastts;
+                       }
                }
        }
        /* Get a pointer to the header */
@@ -933,7 +1076,7 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
        rtpheader[1] = htonl(rtp->lastts);
        rtpheader[2] = htonl(rtp->ssrc); 
        if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
-               res = sendto(rtp->s, (void *)rtpheader, f->datalen + hdrlen, 0, &rtp->them, sizeof(rtp->them));
+               res = sendto(rtp->s, (void *)rtpheader, f->datalen + hdrlen, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
                if (res <0) 
                        ast_log(LOG_NOTICE, "RTP Transmission error to %s:%d: %s\n", inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
 #if 0
@@ -971,13 +1114,13 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
 
        codec = ast_rtp_lookup_code(rtp, 1, subclass);
        if (codec < 0) {
-               ast_log(LOG_WARNING, "Don't know how to send format %d packets with RTP\n", _f->subclass);
+               ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", ast_getformatname(_f->subclass));
                return -1;
        }
 
        if (rtp->lasttxformat != subclass) {
                /* New format, reset the smoother */
-               ast_log(LOG_DEBUG, "Ooh, format changed from %d to %d\n", rtp->lasttxformat, subclass);
+               ast_log(LOG_DEBUG, "Ooh, format changed from %s to %s\n", ast_getformatname(rtp->lasttxformat), ast_getformatname(subclass));
                rtp->lasttxformat = subclass;
                if (rtp->smoother)
                        ast_smoother_free(rtp->smoother);
@@ -1000,9 +1143,25 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
                while((f = ast_smoother_read(rtp->smoother)))
                        ast_rtp_raw_write(rtp, f, codec);
                break;
+       case AST_FORMAT_ADPCM:
+       case AST_FORMAT_G726:
+               if (!rtp->smoother) {
+                       rtp->smoother = ast_smoother_new(80);
+               }
+               if (!rtp->smoother) {
+                       ast_log(LOG_WARNING, "Unable to create smoother :(\n");
+                       return -1;
+               }
+               ast_smoother_feed(rtp->smoother, _f);
+               
+               while((f = ast_smoother_read(rtp->smoother)))
+                       ast_rtp_raw_write(rtp, f, codec);
+               break;
        case AST_FORMAT_G729A:
                if (!rtp->smoother) {
                        rtp->smoother = ast_smoother_new(20);
+                       if (rtp->smoother)
+                               ast_smoother_set_flags(rtp->smoother, AST_SMOOTHER_FLAG_G729);
                }
                if (!rtp->smoother) {
                        ast_log(LOG_WARNING, "Unable to create g729 smoother :(\n");
@@ -1038,10 +1197,11 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
                        ast_rtp_raw_write(rtp, f, codec);
                break;
        default:        
-               ast_log(LOG_WARNING, "Not sure about sending format %d packets\n", subclass);
+               ast_log(LOG_WARNING, "Not sure about sending format %s packets\n", ast_getformatname(subclass));
                // fall through to...
        case AST_FORMAT_H261:
        case AST_FORMAT_H263:
+       case AST_FORMAT_G723_1:
        case AST_FORMAT_SPEEX:
                // Don't buffer outgoing frames; send them one-per-packet:
                if (_f->offset < hdrlen) {
@@ -1116,37 +1276,30 @@ int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, st
        
        void *pvt0, *pvt1;
        int to;
-
+       int codec0,codec1, oldcodec0, oldcodec1;
+       
        memset(&vt0, 0, sizeof(vt0));
        memset(&vt1, 0, sizeof(vt1));
        memset(&vac0, 0, sizeof(vac0));
        memset(&vac1, 0, sizeof(vac1));
 
-       /* XXX Wait a half a second for things to settle up 
-                       this really should be fixed XXX */
-       ast_autoservice_start(c0);
-       ast_autoservice_start(c1);
-       usleep(500000);
-       ast_autoservice_stop(c0);
-       ast_autoservice_stop(c1);
-
        /* if need DTMF, cant native bridge */
        if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
                return -2;
-       ast_pthread_mutex_lock(&c0->lock);
-       ast_pthread_mutex_lock(&c1->lock);
+       ast_mutex_lock(&c0->lock);
+       ast_mutex_lock(&c1->lock);
        pr0 = get_proto(c0);
        pr1 = get_proto(c1);
        if (!pr0) {
                ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name);
-               ast_pthread_mutex_unlock(&c0->lock);
-               ast_pthread_mutex_unlock(&c1->lock);
+               ast_mutex_unlock(&c0->lock);
+               ast_mutex_unlock(&c1->lock);
                return -1;
        }
        if (!pr1) {
                ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name);
-               ast_pthread_mutex_unlock(&c0->lock);
-               ast_pthread_mutex_unlock(&c1->lock);
+               ast_mutex_unlock(&c0->lock);
+               ast_mutex_unlock(&c1->lock);
                return -1;
        }
        pvt0 = c0->pvt->pvt;
@@ -1163,42 +1316,61 @@ int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, st
                vp1 = NULL;
        if (!p0 || !p1) {
                /* Somebody doesn't want to play... */
-               ast_pthread_mutex_unlock(&c0->lock);
-               ast_pthread_mutex_unlock(&c1->lock);
+               ast_mutex_unlock(&c0->lock);
+               ast_mutex_unlock(&c1->lock);
                return -2;
        }
-       if (pr0->set_rtp_peer(c0, p1, vp1)) 
+       if (pr0->get_codec)
+               codec0 = pr0->get_codec(c0);
+       else
+               codec0 = 0;
+       if (pr1->get_codec)
+               codec1 = pr1->get_codec(c1);
+       else
+               codec1 = 0;
+       if (pr0->get_codec && pr1->get_codec) {
+               /* Hey, we can't do reinvite if both parties speak diffrent codecs */
+               if (!(codec0 & codec1)) {
+                       ast_log(LOG_WARNING, "codec0 = %d is not codec1 = %d, cannot native bridge.\n",codec0,codec1);
+                       ast_mutex_unlock(&c0->lock);
+                       ast_mutex_unlock(&c1->lock);
+                       return -2;
+               }
+       }
+       if (pr0->set_rtp_peer(c0, p1, vp1, codec1)) 
                ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
        else {
                /* Store RTP peer */
                ast_rtp_get_peer(p1, &ac1);
                if (vp1)
-                       ast_rtp_get_peer(p1, &vac1);
+                       ast_rtp_get_peer(vp1, &vac1);
        }
-       if (pr1->set_rtp_peer(c1, p0, vp0))
+       if (pr1->set_rtp_peer(c1, p0, vp0, codec0))
                ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name);
        else {
                /* Store RTP peer */
                ast_rtp_get_peer(p0, &ac0);
                if (vp0)
-                       ast_rtp_get_peer(p0, &vac0);
+                       ast_rtp_get_peer(vp0, &vac0);
        }
-       ast_pthread_mutex_unlock(&c0->lock);
-       ast_pthread_mutex_unlock(&c1->lock);
+       ast_mutex_unlock(&c0->lock);
+       ast_mutex_unlock(&c1->lock);
        cs[0] = c0;
        cs[1] = c1;
        cs[2] = NULL;
+       oldcodec0 = codec0;
+       oldcodec1 = codec1;
        for (;;) {
                if ((c0->pvt->pvt != pvt0)  ||
                        (c1->pvt->pvt != pvt1) ||
                        (c0->masq || c0->masqr || c1->masq || c1->masqr)) {
                                ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n");
                                if (c0->pvt->pvt == pvt0) {
-                                       if (pr0->set_rtp_peer(c0, NULL, NULL)) 
+                                       if (pr0->set_rtp_peer(c0, NULL, NULL, 0)) 
                                                ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
                                }
                                if (c1->pvt->pvt == pvt1) {
-                                       if (pr1->set_rtp_peer(c1, NULL, NULL)) 
+                                       if (pr1->set_rtp_peer(c1, NULL, NULL, 0)) 
                                                ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
                                }
                                /* Tell it to try again later */
@@ -1206,27 +1378,47 @@ int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, st
                }
                to = -1;
                ast_rtp_get_peer(p1, &t1);
+               ast_rtp_get_peer(p0, &t0);
+               if (pr0->get_codec)
+                       codec0 = pr0->get_codec(c0);
+               if (pr1->get_codec)
+                       codec1 = pr1->get_codec(c1);
                if (vp1)
                        ast_rtp_get_peer(vp1, &vt1);
                if (vp0)
                        ast_rtp_get_peer(vp0, &vt0);
-               if (inaddrcmp(&t1, &ac1) || (vp1 && inaddrcmp(&vt1, &vac1))) {
-                       ast_log(LOG_DEBUG, "Oooh, '%s' changed end address\n", c1->name);
-                       if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL)) 
+               if (inaddrcmp(&t1, &ac1) || (vp1 && inaddrcmp(&vt1, &vac1)) || (codec1 != oldcodec1)) {
+                       ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n", 
+                               c1->name, inet_ntoa(t1.sin_addr), ntohs(t1.sin_port), codec1);
+                       ast_log(LOG_DEBUG, "Oooh, '%s' changed end vaddress to %s:%d (format %d)\n", 
+                               c1->name, inet_ntoa(vt1.sin_addr), ntohs(vt1.sin_port), codec1);
+                       ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", 
+                               c1->name, inet_ntoa(ac1.sin_addr), ntohs(ac1.sin_port), oldcodec1);
+                       ast_log(LOG_DEBUG, "Oooh, '%s' wasv %s:%d/(format %d)\n", 
+                               c1->name, inet_ntoa(vac1.sin_addr), ntohs(vac1.sin_port), oldcodec1);
+                       if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, codec1)) 
                                ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
                        memcpy(&ac1, &t1, sizeof(ac1));
                        memcpy(&vac1, &vt1, sizeof(vac1));
+                       oldcodec1 = codec1;
                }
                if (inaddrcmp(&t0, &ac0) || (vp0 && inaddrcmp(&vt0, &vac0))) {
-                       ast_log(LOG_DEBUG, "Oooh, '%s' changed end address\n", c0->name);
-                       if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL))
+                       ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n", 
+                               c0->name, inet_ntoa(t0.sin_addr), ntohs(t0.sin_port), codec0);
+                       ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", 
+                               c0->name, inet_ntoa(ac0.sin_addr), ntohs(ac0.sin_port), oldcodec0);
+                       if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, codec0))
                                ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
                        memcpy(&ac0, &t0, sizeof(ac0));
                        memcpy(&vac0, &vt0, sizeof(vac0));
+                       oldcodec0 = codec0;
                }
                who = ast_waitfor_n(cs, 2, &to);
                if (!who) {
                        ast_log(LOG_DEBUG, "Ooh, empty read...\n");
+                       /* check for hagnup / whentohangup */
+                       if (ast_check_hangup(c0) || ast_check_hangup(c1))
+                               break;
                        continue;
                }
                f = ast_read(who);
@@ -1237,17 +1429,19 @@ int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, st
                        *rc = who;
                        ast_log(LOG_DEBUG, "Oooh, got a %s\n", f ? "digit" : "hangup");
                        if ((c0->pvt->pvt == pvt0) && (!c0->_softhangup)) {
-                               if (pr0->set_rtp_peer(c0, NULL, NULL)) 
+                               if (pr0->set_rtp_peer(c0, NULL, NULL, 0)) 
                                        ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
                        }
                        if ((c1->pvt->pvt == pvt1) && (!c1->_softhangup)) {
-                               if (pr1->set_rtp_peer(c1, NULL, NULL)) 
+                               if (pr1->set_rtp_peer(c1, NULL, NULL, 0)) 
                                        ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
                        }
                        /* That's all we needed */
                        return 0;
                } else {
-                       if ((f->frametype == AST_FRAME_DTMF) || (f->frametype == AST_FRAME_VOICE)) {
+                       if ((f->frametype == AST_FRAME_DTMF) || 
+                               (f->frametype == AST_FRAME_VOICE) || 
+                               (f->frametype == AST_FRAME_VIDEO)) {
                                /* Forward voice or DTMF frames if they happen upon us */
                                if (who == c0) {
                                        ast_write(c1, f);