[svn-commits] trunk r32597 - in /trunk: ./ channels/ include/asterisk/

svn-commits at lists.digium.com svn-commits at lists.digium.com
Tue Jun 6 09:09:34 MST 2006


Author: oej
Date: Tue Jun  6 11:09:33 2006
New Revision: 32597

URL: http://svn.digium.com/view/asterisk?rev=32597&view=rev
Log:
Merge of the "sdpcleanup" branch. Thanks to John Martin for a lot of tests
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.


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

Modified: trunk/channel.c
URL: http://svn.digium.com/view/asterisk/trunk/channel.c?rev=32597&r1=32596&r2=32597&view=diff
==============================================================================
--- trunk/channel.c (original)
+++ trunk/channel.c Tue Jun  6 11:09:33 2006
@@ -539,7 +539,7 @@
 	}
 }
 
-/*! \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 @@
 		/*! 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 @@
 	int fmt;
 	int res;
 	int foo;
+	int videoformat = format & AST_FORMAT_VIDEO_MASK;
 
 	if (!cause)
 		cause = &foo;
@@ -2629,7 +2632,7 @@
 			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 @@
 		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) {

Modified: trunk/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_sip.c?rev=32597&r1=32596&r2=32597&view=diff
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Tue Jun  6 11:09:33 2006
@@ -1260,6 +1260,7 @@
 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 @@
 
 
 /*! \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,16 +3274,49 @@
 		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);
@@ -3297,7 +3335,7 @@
 		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 @@
 	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 @@
 	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;	/* Peer's video capabilities */
-	struct sockaddr_in sin;
+	int vpeercapability = 0, vpeernoncodeccapability = 0;
+	struct sockaddr_in sin;		/*!< media socket address */
+	struct sockaddr_in vsin;	/*!< Video socket address */
+
 	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 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);
-	struct ast_channel *bridgepeer = NULL;
-
+		
 	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 @@
 		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 @@
 				}
 				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 @@
 				}
 				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);
-	}
-
-	/* 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;
-	
+			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];
+		}
+	}
+
 	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;
-	}
-
-	if (!p->owner) 	/* There's no open channel owning us */
+
+	/* 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 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 @@
 			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,9 +4445,11 @@
 		}
 		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 @@
 	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 @@
 		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 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 @@
 	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);
-
-	len = 0;
+	int needvideo = FALSE;
+	int debug = sip_debug_test_pvt(p);
+
+	m_video[0] = '\0';	/* Reset the video media string if it's not needed */
+
 	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 @@
 		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_addr = p->vredirip.sin_addr;
 			vdest.sin_port = p->vredirip.sin_port;
-			vdest.sin_addr = p->vredirip.sin_addr;
 		} 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;
-	}
-
-	/* Start by sending our preferred codecs */
+		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 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 @@
 		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 @@
 					 &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 @@
 				    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,38 +5296,38 @@
 		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");
-
-	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);
+	if (needvideo)
+		ast_build_string(&m_video_next, &m_video_left, "\r\n");
+
+	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 @@
 			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 @@
 	}
 }
 
-/*! \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 @@
 			}
 		}
 		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 @@
 			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 @@
 		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 @@
 		}
 		
 		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 @@

[... 168 lines stripped ...]


More information about the svn-commits mailing list