Merge of the "sdpcleanup" branch. Thanks to John Martin for a lot of tests
authorOlle Johansson <oej@edvina.net>
Tue, 6 Jun 2006 16:09:33 +0000 (16:09 +0000)
committerOlle Johansson <oej@edvina.net>
Tue, 6 Jun 2006 16:09:33 +0000 (16:09 +0000)
and some patches (all disclaimed).

- Don't change RTP properties if we reject a re-INVITE
- Don't add video to an outbound channel if there's no video on the inbound channel
- Don't include video in the "preferred codec" list for codec selection
- Clean up and document code that parses and adds SDP attachments

Since we do not transcode video, we can't handle video the same way as audio. This is a
bug fix patch. In future releases, we need to work on a solution for video negotiation,
not codecs but formats and framerates instead.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@32597 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channel.c
channels/chan_sip.c
frame.c
include/asterisk/rtp.h
include/asterisk/translate.h
rtp.c

index 214a79c..ed86d52 100644 (file)
--- a/channel.c
+++ b/channel.c
@@ -539,7 +539,7 @@ char *ast_transfercapability2str(int transfercapability)
        }
 }
 
-/*! \brief Pick the best codec */
+/*! \brief Pick the best audio codec */
 int ast_best_codec(int fmts)
 {
        /* This just our opinion, expressed in code.  We are asked to choose
@@ -572,7 +572,9 @@ int ast_best_codec(int fmts)
                /*! Down to G.723.1 which is proprietary but at least designed for voice */
                AST_FORMAT_G723_1,
        };
-       
+
+       /* Strip out video */
+       fmts &= AST_FORMAT_AUDIO_MASK;
        
        /* Find the first preferred codec in the format given */
        for (x=0; x < (sizeof(prefs) / sizeof(prefs[0]) ); x++)
@@ -2614,6 +2616,7 @@ struct ast_channel *ast_request(const char *type, int format, void *data, int *c
        int fmt;
        int res;
        int foo;
+       int videoformat = format & AST_FORMAT_VIDEO_MASK;
 
        if (!cause)
                cause = &foo;
@@ -2629,7 +2632,7 @@ struct ast_channel *ast_request(const char *type, int format, void *data, int *c
                        continue;
 
                capabilities = chan->tech->capabilities;
-               fmt = format;
+               fmt = format & AST_FORMAT_AUDIO_MASK;
                res = ast_translator_best_choice(&fmt, &capabilities);
                if (res < 0) {
                        ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %d) to %d\n", type, chan->tech->capabilities, format);
@@ -2640,7 +2643,7 @@ struct ast_channel *ast_request(const char *type, int format, void *data, int *c
                if (!chan->tech->requester)
                        return NULL;
                
-               if (!(c = chan->tech->requester(type, capabilities, data, cause)))
+               if (!(c = chan->tech->requester(type, capabilities | videoformat, data, cause)))
                        return NULL;
 
                if (c->_state == AST_STATE_DOWN) {
index 6ed605b..c544c41 100644 (file)
@@ -1260,6 +1260,7 @@ static struct ast_rtp *sip_get_vrtp_peer(struct ast_channel *chan);
 static int sip_get_codec(struct ast_channel *chan);
 static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p);
 
+
 /*! \brief Definition of this channel for PBX channel registration */
 static const struct ast_channel_tech sip_tech = {
        .type = "SIP",
@@ -3252,13 +3253,17 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
 
 
 /*! \brief Initiate a call in the SIP channel
-       called from sip_request_call (calls from the pbx ) */
+       called from sip_request_call (calls from the pbx ) for outbound channels
+       and from handle_request_invite for inbound channels
+       
+*/
 static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *title)
 {
        struct ast_channel *tmp;
        struct ast_variable *v = NULL;
        int fmt;
        int what;
+       int needvideo = 0;
        
        ast_mutex_unlock(&i->lock);
        /* Don't hold a sip pvt lock while we allocate a channel */
@@ -3269,17 +3274,50 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
                return NULL;
        }
        tmp->tech = &sip_tech;
+
        /* Select our native format based on codec preference until we receive
           something from another device to the contrary. */
-       if (i->jointcapability)
+       if (i->jointcapability)         /* The joint capabilities of us and peer */
                what = i->jointcapability;
-       else if (i->capability)
+       else if (i->capability)         /* Our configured capability for this peer */
                what = i->capability;
        else
-               what = global_capability;
+               what = global_capability;       /* Global codec support */
+
+       /* Set the native formats for audio  and merge in video */
        tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
+       if (option_debug > 2) {
+               char buf[BUFSIZ];
+               ast_log(LOG_DEBUG, "*** Our native formats are %s \n", ast_getformatname_multiple(buf, BUFSIZ, tmp->nativeformats));
+               ast_log(LOG_DEBUG, "*** Joint capabilities are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->jointcapability));
+               ast_log(LOG_DEBUG, "*** Our capabilities are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->capability));
+               ast_log(LOG_DEBUG, "*** AST_CODEC_CHOOSE formats are %s \n", ast_getformatname_multiple(buf, BUFSIZ, ast_codec_choose(&i->prefs, what, 1)));
+               if (i->prefcodec)
+                       ast_log(LOG_DEBUG, "*** Our preferred formats from the incoming channel are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->prefcodec));
+       }
+
+       /* XXX Why are we choosing a codec from the native formats?? */
        fmt = ast_best_codec(tmp->nativeformats);
 
+       /* If we have a prefcodec setting, we have an inbound channel that set a 
+          preferred format for this call. Otherwise, we check the jointcapability
+          We also check for vrtp. If it's not there, we are not allowed do any video anyway.
+        */
+       if (i->vrtp) {
+               if (i->prefcodec)
+                       needvideo = i->prefcodec & AST_FORMAT_VIDEO_MASK;       /* Outbound call */
+               else
+                       needvideo = i->jointcapability & AST_FORMAT_VIDEO_MASK; /* Inbound call */
+       }
+
+       if (option_debug > 2) {
+               if (needvideo) 
+                       ast_log(LOG_DEBUG, "This channel can handle video! HOLLYWOOD next!\n");
+               else
+                       ast_log(LOG_DEBUG, "This channel will not be able to handle video.\n");
+       }
+
+
        if (title)
                ast_string_field_build(tmp, name, "SIP/%s-%04lx", title, ast_random() & 0xffff);
        else if (strchr(i->fromdomain,':'))
@@ -3297,7 +3335,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
                tmp->fds[0] = ast_rtp_fd(i->rtp);
                tmp->fds[1] = ast_rtcp_fd(i->rtp);
        }
-       if (i->vrtp) {
+       if (needvideo && i->vrtp) {
                tmp->fds[2] = ast_rtp_fd(i->vrtp);
                tmp->fds[3] = ast_rtcp_fd(i->vrtp);
        }
@@ -4038,7 +4076,9 @@ static int find_sdp(struct sip_request *req)
        return 0;
 }
 
-/*! \brief Process SIP SDP, select formats and activate RTP channels */
+/*! \brief Process SIP SDP offer, select formats and activate RTP channels
+       If offer is rejected, we will not change any properties of the call
+*/
 static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 {
        const char *m;          /* SDP media offer */
@@ -4047,33 +4087,49 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
        char host[258];
        char iabuf[INET_ADDRSTRLEN];
        int len = -1;
-       int portno = -1;        /* Audio port */
-       int vportno = -1;       /* Video port */
+       int portno = -1;                /*!< RTP Audio port number */
+       int vportno = -1;               /*!< RTP Video port number */
 
        /* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */     
        int peercapability, peernoncodeccapability;
+       int vpeercapability = 0, vpeernoncodeccapability = 0;
+       struct sockaddr_in sin;         /*!< media socket address */
+       struct sockaddr_in vsin;        /*!< Video socket address */
 
-       int vpeercapability=0, vpeernoncodeccapability=0;       /* Peer's video capabilities */
-       struct sockaddr_in sin;
        const char *codecs;
-       struct hostent *hp;
-       struct ast_hostent ahp;
+       struct hostent *hp;             /*!< RTP Audio host IP */
+       struct hostent *vhp = NULL;     /*!< RTP video host IP */
+       struct ast_hostent audiohp;
+       struct ast_hostent videohp;
        int codec;
        int destiterator = 0;
        int iterator;
        int sendonly = 0;
-       int x, y;
-       int debug = sip_debug_test_pvt(p);
+       int numberofports;
        struct ast_channel *bridgepeer = NULL;
-
+       struct ast_rtp newaudiortp, newvideortp;        /* Buffers for codec handling */
+       int newjointcapability;                         /* Negotiated capability */
+       int newpeercapability;
+       int newnoncodeccapability;
+       int numberofmediastreams = 0;
+       int debug = sip_debug_test_pvt(p);
+               
        if (!p->rtp) {
                ast_log(LOG_ERROR, "Got SDP but have no RTP session allocated.\n");
                return -1;
        }
 
+       /* Initialize the temporary RTP structures we use to evaluate the offer from the peer */
+       memset(&newaudiortp, 0, sizeof(newaudiortp));
+       memset(&newvideortp, 0, sizeof(newvideortp));
+       ast_rtp_pt_default(&newaudiortp);
+       ast_rtp_pt_default(&newvideortp);
+
        /* Update our last rtprx when we receive an SDP, too */
        p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
 
+
+       /* Try to find first media stream */
        m = get_sdp(req, "m");
        destiterator = req->sdp_start;
        c = get_sdp_iterate(&destiterator, req, "c");
@@ -4081,26 +4137,41 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
                return -1;
        }
+
+       /* Check for IPv4 address (not IPv6 yet) */
        if (sscanf(c, "IN IP4 %256s", host) != 1) {
                ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
                return -1;
        }
+
        /* XXX This could block for a long time, and block the main thread! XXX */
-       hp = ast_gethostbyname(host, &ahp);
+       hp = ast_gethostbyname(host, &audiohp);
        if (!hp) {
                ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
                return -1;
        }
+       vhp = hp;       /* Copy to video address as default too */
+       
        iterator = req->sdp_start;
        ast_set_flag(&p->flags[0], SIP_NOVIDEO);        
+
+
+       /* Find media streams in this SDP offer */
        while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
-               int found = 0;
-               if ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &y, &len) == 2) ||
+               int x;
+               int audio = FALSE;
+               numberofmediastreams++;
+
+               if (p->vrtp)
+                       ast_rtp_pt_clear(&newvideortp);  /* Must be cleared in case no m=video line exists */
+               numberofports = 1;
+               if ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2) ||
                    (sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1)) {
-                       found = 1;
+                       audio = TRUE;
+                       /* Found audio stream in this media definition */
                        portno = x;
                        /* Scan through the RTP payload types specified in a "m=" line: */
-                       ast_rtp_pt_clear(p->rtp);
+                       ast_rtp_pt_clear(&newaudiortp);
                        for (codecs = m + len; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
                                if (sscanf(codecs, "%d%n", &codec, &len) != 1) {
                                        ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
@@ -4108,14 +4179,11 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                                }
                                if (debug)
                                        ast_verbose("Found RTP audio format %d\n", codec);
-                               ast_rtp_set_m_type(p->rtp, codec);
+                               ast_rtp_set_m_type(&newaudiortp, codec);
                        }
-               }
-               if (p->vrtp)
-                       ast_rtp_pt_clear(p->vrtp);  /* Must be cleared in case no m=video line exists */
-
-               if (p->vrtp && (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1)) {
-                       found = 1;
+               } else if ((sscanf(m, "video %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2) ||
+                   (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1)) {
+                       /* If it is not audio - is it video ? */
                        ast_clear_flag(&p->flags[0], SIP_NOVIDEO);      
                        vportno = x;
                        /* Scan through the RTP payload types specified in a "m=" line: */
@@ -4126,144 +4194,210 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                                }
                                if (debug)
                                        ast_verbose("Found RTP video format %d\n", codec);
-                               ast_rtp_set_m_type(p->vrtp, codec);
+                               ast_rtp_set_m_type(&newvideortp, codec);
                        }
-               }
-               if (!found )
-                       ast_log(LOG_WARNING, "Unknown SDP media type in offer: %s\n", m);
-       }
-       if (portno == -1 && vportno == -1) {
-               /* No acceptable offer found in SDP */
-               return -2;
-       }
-       /* Check for Media-description-level-address for audio */
-       if (pedanticsipchecking) {
+               } else 
+                       ast_log(LOG_WARNING, "Unsupported SDP media type in offer: %s\n", m);
+               if (numberofports > 1)
+                       ast_log(LOG_WARNING, "SDP offered %d ports for media, not supported by Asterisk. Will try anyway...\n", numberofports);
+               
+
+               /* Check for Media-description-level-address for audio */
                c = get_sdp_iterate(&destiterator, req, "c");
                if (!ast_strlen_zero(c)) {
                        if (sscanf(c, "IN IP4 %256s", host) != 1) {
                                ast_log(LOG_WARNING, "Invalid secondary host in c= line, '%s'\n", c);
                        } else {
                                /* XXX This could block for a long time, and block the main thread! XXX */
-                               hp = ast_gethostbyname(host, &ahp);
-                               if (!hp) {
-                                       ast_log(LOG_WARNING, "Unable to lookup host in secondary c= line, '%s'\n", c);
-                               }
+                               if (audio) {
+                                       if ( !(hp = ast_gethostbyname(host, &audiohp)))
+                                               ast_log(LOG_WARNING, "Unable to lookup RTP Audio host in secondary c= line, '%s'\n", c);
+                               } else if (!(vhp = ast_gethostbyname(host, &videohp)))
+                                       ast_log(LOG_WARNING, "Unable to lookup RTP video host in secondary c= line, '%s'\n", c);
                        }
+
                }
        }
+       if (portno == -1 && vportno == -1)
+               /* No acceptable offer found in SDP  - we have no ports */
+               /* Do not change RTP or VRTP if this is a re-invite */
+               return -2;
+
+       if (numberofmediastreams > 2)
+               /* We have too many media streams, fail this offer */
+               return -3;
+
        /* RTP addresses and ports for audio and video */
        sin.sin_family = AF_INET;
+       vsin.sin_family = AF_INET;
        memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+       if (vhp)
+               memcpy(&vsin.sin_addr, vhp->h_addr, sizeof(vsin.sin_addr));
+               
 
        /* Setup audio port number */
        sin.sin_port = htons(portno);
-       if (p->rtp && sin.sin_port) {
-               ast_rtp_set_peer(p->rtp, &sin);
-               if (debug) {
-                       ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(iabuf,sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
-               }
-       }
-       /* Check for Media-description-level-address for video */
-       if (pedanticsipchecking) {
-               c = get_sdp_iterate(&destiterator, req, "c");
-               if (!ast_strlen_zero(c)) {
-                       if (sscanf(c, "IN IP4 %256s", host) != 1) {
-                               ast_log(LOG_WARNING, "Invalid secondary host in c= line, '%s'\n", c);
-                       } else {
-                               /* XXX This could block for a long time, and block the main thread! XXX */
-                               hp = ast_gethostbyname(host, &ahp);
-                               if (!hp) {
-                                       ast_log(LOG_WARNING, "Unable to lookup host in secondary c= line, '%s'\n", c);
-                               }
-                       }
-               }
-       }
        /* Setup video port number */
-       sin.sin_port = htons(vportno);
-       if (p->vrtp && sin.sin_port) {
-               ast_rtp_set_peer(p->vrtp, &sin);
-               if (debug) {
-                       ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(iabuf,sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
-               }
-       }
+       if (vportno != -1)
+               vsin.sin_port = htons(vportno);
 
        /* Next, scan through each "a=rtpmap:" line, noting each
         * specified RTP payload type (with corresponding MIME subtype):
         */
+       /* XXX This needs to be done per media stream, since it's media stream specific */
        iterator = req->sdp_start;
        while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
                char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
                if (!strcasecmp(a, "sendonly")) {
-                       sendonly=1;
+                       sendonly = 1;
                        continue;
-               }
-               if (!strcasecmp(a, "sendrecv")) {
-                       sendonly=0;
-               }
-               if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue;
+               }  else if (!strcasecmp(a, "sendrecv")) {
+                       sendonly = 0;
+                       continue;
+               } else if (option_debug) {
+                       /* If we're debugging, check for unsupported sdp options */
+                       if (!strcasecmp(a, "inactive")) {
+                               /* Inactive media streams: Not supported */
+                               if (debug)
+                                       ast_verbose("Got unsupported a:inactive in SDP offer \n");
+                               continue;
+                       } else if (!strncasecmp(a, "rtcp:", (size_t) 5)) {
+                               if (debug)
+                                       ast_verbose("Got unsupported a:rtcp in SDP offer \n");
+                               continue;
+                       } else if (!strncasecmp(a, "fmtp:", (size_t) 5)) {
+                               /* Format parameters:  Not supported */
+                               /* Note: This is used for codec parameters, like bitrate for
+                                       G722 and video formats for H263 and H264 
+                                       See RFC2327 for an example */
+                               if (debug)
+                                       ast_verbose("Got unsupported a:fmtp in SDP offer \n");
+                               continue;
+                       } else if (!strncasecmp(a, "framerate:", (size_t) 10)) {
+                               /* Video stuff:  Not supported */
+                               if (debug)
+                                       ast_verbose("Got unsupported a:framerate in SDP offer \n");
+                               continue;
+                       } else if (!strncasecmp(a, "maxprate:", (size_t) 9)) {
+                               /* Video stuff:  Not supported */
+                               if (debug)
+                                       ast_verbose("Got unsupported a:maxprate in SDP offer \n");
+                               continue;
+                       } else if (!strncasecmp(a, "crypto:", (size_t) 7)) {
+                               /* SRTP stuff, not yet supported */
+                               if (debug)
+                                       ast_verbose("Got unsupported a:crypto in SDP offer \n");
+                               continue;
+                       } else if (!strncasecmp(a, "ptime:", (size_t) 6)) {
+                               if (debug)
+                                       ast_verbose("Got unsupported a:ptime in SDP offer \n");
+                               continue;
+                       }
+               } else if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) 
+                       continue;
+               /* We have a rtpmap to handle */
                if (debug)
-                       ast_verbose("Found description format %s\n", mimeSubtype);
+                       ast_verbose("Found description format %s for ID %d\n", mimeSubtype, codec);
+
                /* Note: should really look at the 'freq' and '#chans' params too */
-               ast_rtp_set_rtpmap_type(p->rtp, codec, "audio", mimeSubtype);
+               ast_rtp_set_rtpmap_type(&newaudiortp, codec, "audio", mimeSubtype);
                if (p->vrtp)
-                       ast_rtp_set_rtpmap_type(p->vrtp, codec, "video", mimeSubtype);
+                       ast_rtp_set_rtpmap_type(&newvideortp, codec, "video", mimeSubtype);
+       }
+
+       /* Now gather all of the codecs that we are asked for: */
+       ast_rtp_get_current_formats(&newaudiortp, &peercapability, &peernoncodeccapability);
+       ast_rtp_get_current_formats(&newvideortp, &vpeercapability, &vpeernoncodeccapability);
+
+       newjointcapability = p->capability & (peercapability | vpeercapability);
+       newpeercapability = (peercapability | vpeercapability);
+       newnoncodeccapability = noncodeccapability & peernoncodeccapability;
+               
+               
+       if (debug) {
+               /* shame on whoever coded this.... */
+               char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ], s4[BUFSIZ];
+
+               ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s, combined - %s\n",
+                       ast_getformatname_multiple(s1, BUFSIZ, p->capability),
+                       ast_getformatname_multiple(s2, BUFSIZ, newpeercapability),
+                       ast_getformatname_multiple(s3, BUFSIZ, vpeercapability),
+                       ast_getformatname_multiple(s4, BUFSIZ, newjointcapability));
+
+               ast_verbose("Non-codec capabilities (dtmf): us - %s, peer - %s, combined - %s\n",
+                       ast_rtp_lookup_mime_multiple(s1, BUFSIZ, noncodeccapability, 0),
+                       ast_rtp_lookup_mime_multiple(s2, BUFSIZ, peernoncodeccapability, 0),
+                       ast_rtp_lookup_mime_multiple(s3, BUFSIZ, newnoncodeccapability, 0));
+       }
+       if (!newjointcapability) {
+               ast_log(LOG_NOTICE, "No compatible codecs, not accepting this offer!\n");
+               /* Do NOT Change current setting */
+               return -1;
+       }
+
+       /* We are now ready to change the sip session and p->rtp and p->vrtp with the offered codecs, since
+               they are acceptable */
+       p->jointcapability = newjointcapability;        /* Our joint codec profile for this call */
+       p->peercapability = newpeercapability;          /* The other sides capability in latest offer */
+       p->noncodeccapability = newnoncodeccapability;  /* DTMF capabilities */
+
+       {
+               int i;
+               /* Copy payload types from source to destination */
+               for (i=0; i < MAX_RTP_PT; ++i) {
+                       p->rtp->current_RTP_PT[i]= newaudiortp.current_RTP_PT[i];
+                       if (p->vrtp) 
+                               p->vrtp->current_RTP_PT[i]= newvideortp.current_RTP_PT[i];
+               }
        }
 
-       /* Now gather all of the codecs that were asked for: */
-       ast_rtp_get_current_formats(p->rtp,
-                               &peercapability, &peernoncodeccapability);
-       if (p->vrtp)
-               ast_rtp_get_current_formats(p->vrtp,
-                               &vpeercapability, &vpeernoncodeccapability);
-       p->jointcapability = p->capability & (peercapability | vpeercapability);
-       p->peercapability = (peercapability | vpeercapability);
-       p->noncodeccapability = noncodeccapability & peernoncodeccapability;
-       
        if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO) {
                ast_clear_flag(&p->flags[0], SIP_DTMF);
-               if (p->noncodeccapability & AST_RTP_DTMF) {
+               if (newnoncodeccapability & AST_RTP_DTMF) {
                        /* XXX Would it be reasonable to drop the DSP at this point? XXX */
                        ast_set_flag(&p->flags[0], SIP_DTMF_RFC2833);
                } else {
                        ast_set_flag(&p->flags[0], SIP_DTMF_INBAND);
                }
        }
-       
-       if (debug) {
-               /* shame on whoever coded this.... */
-               const unsigned slen=512;
-               char s1[slen], s2[slen], s3[slen], s4[slen];
 
-               ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s, combined - %s\n",
-                       ast_getformatname_multiple(s1, slen, p->capability),
-                       ast_getformatname_multiple(s2, slen, peercapability),
-                       ast_getformatname_multiple(s3, slen, vpeercapability),
-                       ast_getformatname_multiple(s4, slen, p->jointcapability));
-
-               ast_verbose("Non-codec capabilities: us - %s, peer - %s, combined - %s\n",
-                       ast_rtp_lookup_mime_multiple(s1, slen, noncodeccapability, 0),
-                       ast_rtp_lookup_mime_multiple(s2, slen, peernoncodeccapability, 0),
-                       ast_rtp_lookup_mime_multiple(s3, slen, p->noncodeccapability, 0));
-       }
-       if (!p->jointcapability) {
-               ast_log(LOG_NOTICE, "No compatible codecs!\n");
-               return -1;
+       /* Setup audio port number */
+       if (p->rtp && sin.sin_port) {
+               ast_rtp_set_peer(p->rtp, &sin);
+               if (debug)
+                       ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(iabuf,sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
+       }
+
+       /* Setup video port number */
+       if (p->vrtp && vsin.sin_port) {
+               ast_rtp_set_peer(p->vrtp, &vsin);
+               if (debug) 
+                       ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(iabuf,sizeof(iabuf), vsin.sin_addr), ntohs(vsin.sin_port));
+       }
+
+       /* Ok, we're going with this offer */
+       if (option_debug > 1) {
+               char buf[BUFSIZ];
+               ast_log(LOG_DEBUG, "We're settling with these formats: %s\n", ast_getformatname_multiple(buf, BUFSIZ, p->jointcapability));
        }
 
-       if (!p->owner)  /* There's no open channel owning us */
+       if (!p->owner)  /* There's no open channel owning us so we can return here. For a re-invite or so, we proceed */
                return 0;
 
+
        if (!(p->owner->nativeformats & p->jointcapability & AST_FORMAT_AUDIO_MASK)) {
-               const unsigned slen=512;
-               char s1[slen], s2[slen];
-               ast_log(LOG_DEBUG, "Oooh, we need to change our formats since our peer supports only %s and not %s\n", 
-                               ast_getformatname_multiple(s1, slen, p->jointcapability),
-                               ast_getformatname_multiple(s2, slen, p->owner->nativeformats));
+               if (debug) {
+                       char s1[BUFSIZ], s2[BUFSIZ];
+                       ast_log(LOG_DEBUG, "Oooh, we need to change our audio formats since our peer supports only %s and not %s\n", 
+                               ast_getformatname_multiple(s1, BUFSIZ, p->jointcapability),
+                               ast_getformatname_multiple(s2, BUFSIZ, p->owner->nativeformats));
+               }
                p->owner->nativeformats = ast_codec_choose(&p->prefs, p->jointcapability, 1) | (p->capability & vpeercapability);
                ast_set_read_format(p->owner, p->owner->readformat);
                ast_set_write_format(p->owner, p->owner->writeformat);
        }
-       if ((bridgepeer=ast_bridged_channel(p->owner))) {
+
+       if ((bridgepeer = ast_bridged_channel(p->owner))) {
                /* We have a bridge */
                /* Turn on/off music on hold if we are holding/unholding */
                if (sin.sin_addr.s_addr && !sendonly) {
@@ -4277,12 +4411,15 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                        ast_moh_start(bridgepeer, NULL);
                        if (sendonly)
                                ast_rtp_stop(p->rtp);
+                       /* RTCP needs to go ahead, even if we're on hold!!! */
+
                        /* Activate a re-invite */
                        ast_queue_frame(p->owner, &ast_null_frame);
                }
        }
 
        /* Manager Hold and Unhold events must be generated, if necessary */
+       /* XXX Support for sendonly/recvonly needs to be fixed !!! */
        if (sin.sin_addr.s_addr && !sendonly) {
                append_history(p, "Unhold", "%s", req->data);
 
@@ -4308,10 +4445,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                }
                ast_set_flag(&p->flags[0], SIP_CALL_ONHOLD);
        }
+       
 
        return 0;
 }
 
+
 /*! \brief Add header to SIP message */
 static int add_header(struct sip_request *req, const char *var, const char *value)
 {
@@ -4885,6 +5024,7 @@ static int add_vidupdate(struct sip_request *req)
        return 0;
 }
 
+/*! \brief Add codec offer to SDP offer/answer body in INVITE or 200 OK */
 static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
                             char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
                             int debug)
@@ -4905,6 +5045,7 @@ static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate
                ast_build_string(a_buf, a_size, "a=fmtp:%d annexb=no\r\n", rtp_code);
 }
 
+/*! \brief Add RFC 2833 DTMF offer to SDP */
 static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
                                char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
                                int debug)
@@ -4929,21 +5070,25 @@ static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_
 static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
 {
        int len = 0;
-       int pref_codec;
        int alreadysent = 0;
+
        struct sockaddr_in sin;
        struct sockaddr_in vsin;
-       char v[256];
-       char s[256];
-       char o[256];
-       char c[256];
-       char t[256];
-       char b[256];
+       struct sockaddr_in dest;
+       struct sockaddr_in vdest = { 0, };
+
+       /* SDP fields */
+       char *version =         "v=0\r\n";              /* Protocol version */
+       char *subject =         "s=session\r\n";        /* Subject of the session */
+       char owner[256];                                /* Session owner/creator */
+       char connection[256];                           /* Connection data */
+       char *stime = "t=0 0\r\n";                      /* Time the session is active */
+       char bandwidth[256] = "";                       /* Max bitrate */
        char *hold;
-       char m_audio[256];
-       char m_video[256];
-       char a_audio[1024];
-       char a_video[1024];
+       char m_audio[256];                              /* Media declaration line for audio */
+       char m_video[256];                              /* Media declaration line for video */
+       char a_audio[1024];                             /* Attributes for audio */
+       char a_video[1024];                             /* Attributes for video */
        char *m_audio_next = m_audio;
        char *m_video_next = m_video;
        size_t m_audio_left = sizeof(m_audio);
@@ -4952,31 +5097,33 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
        char *a_video_next = a_video;
        size_t a_audio_left = sizeof(a_audio);
        size_t a_video_left = sizeof(a_video);
+
        char iabuf[INET_ADDRSTRLEN];
        int x;
        int capability;
-       struct sockaddr_in dest;
-       struct sockaddr_in vdest = { 0, };
-       int debug;
-       
-       debug = sip_debug_test_pvt(p);
+       int needvideo = FALSE;
+       int debug = sip_debug_test_pvt(p);
+
+       m_video[0] = '\0';      /* Reset the video media string if it's not needed */
 
-       len = 0;
        if (!p->rtp) {
                ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
                return -1;
        }
-       capability = p->jointcapability;
-               
+
+       /* Set RTP Session ID and version */
        if (!p->sessionid) {
                p->sessionid = getpid();
                p->sessionversion = p->sessionid;
        } else
                p->sessionversion++;
+
+       /* Get our addresses */
        ast_rtp_get_us(p->rtp, &sin);
        if (p->vrtp)
                ast_rtp_get_us(p->vrtp, &vsin);
 
+       /* Is this a re-invite to move the media out, then use the original offer from caller  */
        if (p->redirip.sin_addr.s_addr) {
                dest.sin_port = p->redirip.sin_port;
                dest.sin_addr = p->redirip.sin_addr;
@@ -4987,60 +5134,109 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
                dest.sin_port = sin.sin_port;
        }
 
-       /* Determine video destination */
-       if (p->vrtp) {
+       /* Ok, let's start working with codec selection here */
+       capability = p->jointcapability;
+
+       if (option_debug > 1) {
+               char codecbuf[BUFSIZ];
+               ast_log(LOG_DEBUG, "** Our capability: %s Video flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability), ast_test_flag(&p->flags[0], SIP_NOVIDEO) ? "True" : "False");
+               ast_log(LOG_DEBUG, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec));
+       }
+
+       /* Check if we need video in this call */
+       if((capability & AST_FORMAT_VIDEO_MASK) && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
+               if (p->vrtp) {
+                       needvideo = TRUE;
+                       if (option_debug > 1)
+                               ast_log(LOG_DEBUG, "This call needs video offers! \n");
+               } else if (option_debug > 1)
+                       ast_log(LOG_DEBUG, "This call needs video offers, but there's no video support enabled ! \n");
+       }
+               
+
+       /* Ok, we need video. Let's add what we need for video and set codecs.
+          Video is handled differently than audio since we can not transcode. */
+       if (needvideo) {
+
+               /* Determine video destination */
                if (p->vredirip.sin_addr.s_addr) {
-                       vdest.sin_port = p->vredirip.sin_port;
                        vdest.sin_addr = p->vredirip.sin_addr;
+                       vdest.sin_port = p->vredirip.sin_port;
                } else {
                        vdest.sin_addr = p->ourip;
                        vdest.sin_port = vsin.sin_port;
                }
-       }
-       if (debug) {
-               ast_verbose("We're at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(sin.sin_port));       
-               if (p->vrtp)
+               ast_build_string(&m_video_next, &m_video_left, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
+
+               /* Build max bitrate string */
+               if (p->maxcallbitrate)
+                       snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->maxcallbitrate);
+               if (debug) 
                        ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(vsin.sin_port));   
+
+               /* For video, we can't negotiate video offers. Let's compare the incoming call with what we got. */
+               if (p->prefcodec) {
+                       int videocapability = (capability & p->prefcodec) & AST_FORMAT_VIDEO_MASK; /* Outbound call */
+               
+                       /*! \todo XXX We need to select one codec, not many, since there's no transcoding */
+
+                       /* Now, merge this video capability into capability while removing unsupported codecs */
+                       if (!videocapability) {
+                               needvideo = FALSE;
+                               if (option_debug > 2)
+                                       ast_log(LOG_DEBUG, "** No compatible video codecs... Disabling video.\n");
+                       } 
+
+                       /* Replace video capabilities with the new videocapability */
+                       capability = (capability & AST_FORMAT_AUDIO_MASK) | videocapability;
+
+                       if (option_debug > 4) {
+                               char codecbuf[BUFSIZ];
+                               if (videocapability)
+                                       ast_log(LOG_DEBUG, "** Our video codec selection is: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), videocapability));
+                               ast_log(LOG_DEBUG, "** Capability now set to : %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability));
+                       }
+               }
        }
+       if (debug) 
+               ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(sin.sin_port));    
+
+       /* Start building generic SDP headers */
 
        /* We break with the "recommendation" and send our IP, in order that our
           peer doesn't have to ast_gethostbyname() us */
 
-       snprintf(v, sizeof(v), "v=0\r\n");
-       snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", p->sessionid, p->sessionversion, ast_inet_ntoa(iabuf, sizeof(iabuf), dest.sin_addr));
-       snprintf(s, sizeof(s), "s=session\r\n");
-       snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(iabuf, sizeof(iabuf), dest.sin_addr));
-       if ((p->vrtp) &&
-           (!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
-           (capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
-               snprintf(b, sizeof(b), "b=CT:%d\r\n", p->maxcallbitrate);       
-       snprintf(t, sizeof(t), "t=0 0\r\n");
-
+       snprintf(owner, sizeof(owner), "o=root %d %d IN IP4 %s\r\n", p->sessionid, p->sessionversion, ast_inet_ntoa(iabuf, sizeof(iabuf), dest.sin_addr));
+       snprintf(connection, sizeof(connection), "c=IN IP4 %s\r\n", ast_inet_ntoa(iabuf, sizeof(iabuf), dest.sin_addr));
        ast_build_string(&m_audio_next, &m_audio_left, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
-       ast_build_string(&m_video_next, &m_video_left, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
 
        if (ast_test_flag(&p->flags[0], SIP_CALL_ONHOLD))
                hold = "a=recvonly\r\n";
        else
                hold = "a=sendrecv\r\n";
 
-       /* Prefer the codec we were requested to use, first, no matter what */
+       /* Now, start adding audio codecs. These are added in this order:
+               - First what was requested by the calling channel
+               - Then preferences in order from sip.conf device config for this peer/user
+               - Then other codecs in capabilities, including video
+       */
+
+       /* Prefer the audio codec we were requested to use, first, no matter what 
+               Note that p->prefcodec can include video codecs, so mask them out
+        */
        if (capability & p->prefcodec) {
-               if (p->prefcodec <= AST_FORMAT_MAX_AUDIO)
-                       add_codec_to_sdp(p, p->prefcodec, 8000,
-                                        &m_audio_next, &m_audio_left,
-                                        &a_audio_next, &a_audio_left,
-                                        debug);
-               else
-                       add_codec_to_sdp(p, p->prefcodec, 90000,
-                                        &m_video_next, &m_video_left,
-                                        &a_video_next, &a_video_left,
-                                        debug);
-               alreadysent |= p->prefcodec;
+               add_codec_to_sdp(p, p->prefcodec & AST_FORMAT_AUDIO_MASK, 8000,
+                                &m_audio_next, &m_audio_left,
+                                &a_audio_next, &a_audio_left,
+                                debug);
+               alreadysent |= p->prefcodec & AST_FORMAT_AUDIO_MASK;
        }
 
-       /* Start by sending our preferred codecs */
+
+       /* Start by sending our preferred audio codecs */
        for (x = 0; x < 32; x++) {
+               int pref_codec;
+
                if (!(pref_codec = ast_codec_pref_index(&p->prefs, x)))
                        break; 
 
@@ -5050,27 +5246,21 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
                if (alreadysent & pref_codec)
                        continue;
 
-               if (pref_codec <= AST_FORMAT_MAX_AUDIO)
-                       add_codec_to_sdp(p, pref_codec, 8000,
-                                        &m_audio_next, &m_audio_left,
-                                        &a_audio_next, &a_audio_left,
-                                        debug);
-               else
-                       add_codec_to_sdp(p, pref_codec, 90000,
-                                        &m_video_next, &m_video_left,
-                                        &a_video_next, &a_video_left,
-                                        debug);
+               add_codec_to_sdp(p, pref_codec, 8000,
+                                &m_audio_next, &m_audio_left,
+                                &a_audio_next, &a_audio_left,
+                                debug);
                alreadysent |= pref_codec;
        }
 
-       /* Now send any other common codecs, and non-codec formats: */
-       for (x = 1;
-            x <= ((ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO);
-            x <<= 1) {
-               if (!(capability & x))
+       /* Now send any other common audio and video codecs, and non-codec formats: */
+       for (x = 1; x <= (needvideo ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO); x <<= 1) {
+               if (!(capability & x))  /* Codec not requested */
                        continue;
 
-               if (alreadysent & x)
+               ast_log(LOG_DEBUG, "--- Checking codec ... %d\n", x);
+
+               if (alreadysent & x)    /* Already added to SDP */
                        continue;
 
                if (x <= AST_FORMAT_MAX_AUDIO)
@@ -5078,13 +5268,14 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
                                         &m_audio_next, &m_audio_left,
                                         &a_audio_next, &a_audio_left,
                                         debug);
-               else
+               else 
                        add_codec_to_sdp(p, x, 90000,
                                         &m_video_next, &m_video_left,
                                         &a_video_next, &a_video_left,
                                         debug);
        }
 
+       /* Now add DTMF RFC2833 telephony-event as a codec */
        for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
                if (!(p->noncodeccapability & x))
                        continue;
@@ -5095,6 +5286,9 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
                                    debug);
        }
 
+       if (option_debug > 2)
+               ast_log(LOG_DEBUG, "-- Done with adding codecs to SDP\n");
+
        if(!ast_internal_timing_enabled(p->owner))
                ast_build_string(&a_audio_next, &a_audio_left, "a=silenceSupp:off - - - -\r\n");
 
@@ -5102,39 +5296,39 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
                ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
 
        ast_build_string(&m_audio_next, &m_audio_left, "\r\n");
-       ast_build_string(&m_video_next, &m_video_left, "\r\n");
+       if (needvideo)
+               ast_build_string(&m_video_next, &m_video_left, "\r\n");
 
-       len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m_audio) + strlen(a_audio) + strlen(hold);
-       if ((p->vrtp) &&
-           (!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
-           (capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
-               len += strlen(m_video) + strlen(a_video) + strlen(b) + strlen(hold);
+       len = strlen(version) + strlen(subject) + strlen(owner) + strlen(connection) + strlen(stime) + strlen(m_audio) + strlen(a_audio) + strlen(hold);
+       if (needvideo) /* only if video response is appropriate */
+               len += strlen(m_video) + strlen(a_video) + strlen(bandwidth) + strlen(hold);
 
        add_header(resp, "Content-Type", "application/sdp");
        add_header_contentLength(resp, len);
-       add_line(resp, v);
-       add_line(resp, o);
-       add_line(resp, s);
-       add_line(resp, c);
-       if ((p->vrtp) &&
-           (!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
-           (capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
-               add_line(resp, b);
-       add_line(resp, t);
+       add_line(resp, version);
+       add_line(resp, owner);
+       add_line(resp, subject);
+       add_line(resp, connection);
+       if (needvideo)          /* only if video response is appropriate */
+               add_line(resp, bandwidth);
+       add_line(resp, stime);
        add_line(resp, m_audio);
        add_line(resp, a_audio);
        add_line(resp, hold);
-       if ((p->vrtp) &&
-           (!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
-           (capability & VIDEO_CODEC_MASK)) { /* only if video response is appropriate */
+       if (needvideo) { /* only if video response is appropriate */
                add_line(resp, m_video);
                add_line(resp, a_video);
-               add_line(resp, hold);
+               add_line(resp, hold);   /* Repeat hold for the video stream */
        }
 
        /* Update lastrtprx when we send our SDP */
        p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
 
+       if (option_debug > 2) {
+               char buf[BUFSIZ];
+               ast_log(LOG_DEBUG, "Done building SDP. Settling with this capability: %s\n", ast_getformatname_multiple(buf, BUFSIZ, capability));
+       }
+
        return 0;
 }
 
@@ -7744,20 +7938,24 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                        p->pickupgroup = user->pickupgroup;
                        if (user->callingpres)  /* User callingpres setting will override RPID header */
                                p->callingpres = user->callingpres;
-                       p->capability = user->capability;
-                       p->jointcapability = user->capability;
-                       p->maxcallbitrate = user->maxcallbitrate;
-                       if (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) {
-                               ast_rtp_destroy(p->vrtp);
-                               p->vrtp = NULL;
-                       }
-                       if (p->peercapability)
+                       
+                       /* Set default codec settings for this call */
+                       p->capability = user->capability;               /* User codec choice */
+                       p->jointcapability = user->capability;          /* Our codecs */
+                       if (p->peercapability)                          /* AND with peer's codecs */
                                p->jointcapability &= p->peercapability;
                        if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
                            (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
                                p->noncodeccapability |= AST_RTP_DTMF;
                        else
                                p->noncodeccapability &= ~AST_RTP_DTMF;
+
+                       p->maxcallbitrate = user->maxcallbitrate;
+                       /* If we do not support video, remove video from call structure */
+                       if (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) {
+                               ast_rtp_destroy(p->vrtp);
+                               p->vrtp = NULL;
+                       }
                }
                if (user && debug)
                        ast_verbose("Found user '%s'\n", user->name);
@@ -10197,13 +10395,14 @@ static void check_pendings(struct sip_pvt *p)
        }
 }
 
-/*! \brief Handle SIP response in dialogue */
+/*! \brief Handle SIP response to INVITE dialogue */
 static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno)
 {
        int outgoing = ast_test_flag(&p->flags[0], SIP_OUTGOING);
+       int res = 0;
+       int reinvite = (p->owner && p->owner->_state == AST_STATE_UP);
        
        if (option_debug > 3) {
-               int reinvite = (p->owner && p->owner->_state == AST_STATE_UP);
                if (reinvite)
                        ast_log(LOG_DEBUG, "SIP response %d to RE-invite on %s call %s\n", resp, outgoing ? "outgoing" : "incoming", p->callid);
                else
@@ -10241,7 +10440,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
                        }
                }
                if (find_sdp(req)) {
-                       process_sdp(p, req);
+                       res = process_sdp(p, req);
                        if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
                                /* Queue a progress frame only if we have SDP in 180 */
                                ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
@@ -10257,7 +10456,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
                        sip_cancel_destroy(p);
                /* Ignore 183 Session progress without SDP */
                if (find_sdp(req)) {
-                       process_sdp(p, req);
+                       res = process_sdp(p, req);
                        if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
                                /* Queue a progress frame */
                                ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
@@ -10272,8 +10471,13 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
                if (!ast_test_flag(req, SIP_PKT_IGNORE))
                        sip_cancel_destroy(p);
                p->authtries = 0;
-               if (find_sdp(req))
-                       process_sdp(p, req);
+               if (find_sdp(req)) {
+                       if ((res = process_sdp(p, req)) && !ast_test_flag(req, SIP_PKT_IGNORE))
+                               if (!reinvite)
+                                       /* This 200 OK's SDP is not acceptable, so we need to ack, then hangup */
+                                       /* For re-invites, we try to recover */
+                                       ast_set_flag(&p->flags[0], SIP_PENDINGBYE);     
+               }
 
                /* Parse contact header for continued conversation */
                /* When we get 200 OK, we know which device (and IP) to contact for this call */
@@ -10298,7 +10502,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
                }
                
                if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
-                       if (p->owner->_state != AST_STATE_UP) {
+                       if (!reinvite) {
                                ast_queue_control(p->owner, AST_CONTROL_ANSWER);
                        } else {        /* RE-invite */
                                ast_queue_frame(p->owner, &ast_null_frame);
@@ -13460,6 +13664,9 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
                *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;   /* Can't find codec to connect to host */
                return NULL;
        }
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Asked to create a SIP channel with formats: %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), oldformat));
+
        if (!(p = sip_alloc(NULL, NULL, 0, SIP_INVITE))) {
                ast_log(LOG_ERROR, "Unable to build sip pvt data for '%s' (Out of memory or socket error)\n", (char *)data);
                *cause = AST_CAUSE_SWITCH_CONGESTION;
@@ -13509,7 +13716,7 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
 #if 0
        printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "<none>", host);
 #endif
-       p->prefcodec = format;
+       p->prefcodec = oldformat;                               /* Format for this call */
        ast_mutex_lock(&p->lock);
        tmpc = sip_new(p, AST_STATE_DOWN, host);        /* Place the call */
        ast_mutex_unlock(&p->lock);
@@ -14744,10 +14951,13 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struc
                changed = 1;
        }
        if (changed && !ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
-               if (chan->_state != AST_STATE_UP) {
+               if (chan->_state != AST_STATE_UP) {     /* We are in early state */
                        char iabuf[INET_ADDRSTRLEN];
-                       ast_log(LOG_DEBUG, "Early media setting SIP '%s' - Sending early media to %s\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp ? p->redirip.sin_addr : p->ourip));
-               } else if (!p->pendinginvite) {
+                       if (recordhistory)
+                               append_history(p, "ExtInv", "Initial invite sent with remote bridge proposal.");
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Early remote bridge setting SIP '%s' - Sending media to %s\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp ? p->redirip.sin_addr : p->ourip));
+               } else if (!p->pendinginvite) {         /* We are up, and have no outstanding invite */
                        if (option_debug > 2) {
                                char iabuf[INET_ADDRSTRLEN];
                                ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's audio soon redirected to IP %s\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp ? p->redirip.sin_addr : p->ourip));
@@ -14758,6 +14968,7 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struc
                                char iabuf[INET_ADDRSTRLEN];
                                ast_log(LOG_DEBUG, "Deferring reinvite on SIP '%s' - It's audio will be redirected to IP %s\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp ? p->redirip.sin_addr : p->ourip));
                        }
+                       /* We have a pending Invite. Send re-invite when we're done with the invite */
                        ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);   
                }
        }
diff --git a/frame.c b/frame.c
index 51ca3e9..b4ef6dc 100644 (file)
--- a/frame.c
+++ b/frame.c
@@ -1008,9 +1008,12 @@ int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
                        break;
                }
        }
-       if(ret)
+       if(ret & AST_FORMAT_AUDIO_MASK)
                return ret;
 
+       if (option_debug > 3)
+               ast_log(LOG_DEBUG, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
+
        return find_best ? ast_best_codec(formats) : 0;
 }
 
@@ -1034,7 +1037,10 @@ void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char
                                *mask &= ~format;
                }
 
-               if (pref) {
+               /* Set up a preference list for audio. Do not include video in preferences 
+                  since we can not transcode video and have to use whatever is offered
+                */
+               if (pref && (format & AST_FORMAT_AUDIO_MASK)) {
                        if (strcasecmp(this, "all")) {
                                if (allowing)
                                        ast_codec_pref_append(pref, format);
index 5218193..4410d7f 100644 (file)
@@ -40,13 +40,13 @@ extern "C" {
 
 /* Codes for RTP-specific data - not defined by our AST_FORMAT codes */
 /*! DTMF (RFC2833) */
-#define AST_RTP_DTMF            (1 << 0)
+#define AST_RTP_DTMF                   (1 << 0)
 /*! 'Comfort Noise' (RFC3389) */
-#define AST_RTP_CN              (1 << 1)
+#define AST_RTP_CN                     (1 << 1)
 /*! DTMF (Cisco Proprietary) */
-#define AST_RTP_CISCO_DTMF      (1 << 2)
+#define AST_RTP_CISCO_DTMF             (1 << 2)
 /*! Maximum RTP-specific code */
-#define AST_RTP_MAX             AST_RTP_CISCO_DTMF
+#define AST_RTP_MAX                    AST_RTP_CISCO_DTMF
 
 #define MAX_RTP_PT                     256
 
@@ -62,6 +62,9 @@ struct ast_rtp_protocol {
        AST_LIST_ENTRY(ast_rtp_protocol) list;
 };
 
+
+#define FLAG_3389_WARNING              (1 << 0)
+
 typedef int (*ast_rtp_callback)(struct ast_rtp *rtp, struct ast_frame *f, void *data);
 
 
@@ -71,7 +74,6 @@ typedef int (*ast_rtp_callback)(struct ast_rtp *rtp, struct ast_frame *f, void *
  * RTP session is defined on page 9 of RFC 3550: "An association among a set of participants communicating with RTP.  A participant may be involved in multiple RTP sessions at the same time [...]"
  *
  */
-
 /*! \brief The value of each payload format mapping: */
 struct rtpPayloadType {
        int isAstFormat;        /*!< whether the following code is an AST_FORMAT */
index 182330a..29c3fd5 100644 (file)
@@ -23,7 +23,8 @@
 #ifndef _ASTERISK_TRANSLATE_H
 #define _ASTERISK_TRANSLATE_H
 
-#define MAX_FORMAT 32
+//#define MAX_FORMAT 15        /* Do not include video here */
+#define MAX_FORMAT 32  /* Do include video here */
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
diff --git a/rtp.c b/rtp.c
index a503503..1e806f7 100644 (file)
--- a/rtp.c
+++ b/rtp.c
@@ -1350,7 +1350,7 @@ int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, i
        return 1;
 }
 
-/*! \brief  Make a note of a RTP paymoad type that was seen in a SDP "m=" line.
+/*! \brief  Make a note of a RTP payload type that was seen in a SDP "m=" line.
  * By default, use the well-known value for this type (although it may 
  * still be set to a different value by a subsequent "a=rtpmap:" line)
  */
@@ -1359,9 +1359,8 @@ void ast_rtp_set_m_type(struct ast_rtp* rtp, int pt)
        if (pt < 0 || pt > MAX_RTP_PT) 
                return; /* bogus payload type */
 
-       if (static_RTP_PT[pt].code != 0) {
+       if (static_RTP_PT[pt].code != 0) 
                rtp->current_RTP_PT[pt] = static_RTP_PT[pt];
-       }
 } 
 
 /*! \brief Make a note of a RTP payload type (with MIME type) that was seen in
@@ -2245,7 +2244,7 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
        
        /* Make sure we have enough space for RTP header */
        if ((_f->frametype != AST_FRAME_VOICE) && (_f->frametype != AST_FRAME_VIDEO)) {
-               ast_log(LOG_WARNING, "RTP can only send voice\n");
+               ast_log(LOG_WARNING, "RTP can only send voice and video\n");
                return -1;
        }