diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index d129d1e718c3c13976d07a4ae0573c7acdcb8686..a7141b6e1e5dd5c8a75be5b25324dc871d314e11 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -2497,10 +2497,17 @@ static int is_method_allowed(unsigned int *allowed_methods, enum sipmethod metho
 
 /*--- Codec handling / SDP */
 static void try_suggested_sip_codec(struct sip_pvt *p);
-static const char* get_sdp_iterate(int* start, struct sip_request *req, const char *name);
-static const char *get_sdp(struct sip_request *req, const char *name);
+static const char *get_sdp_iterate(int* start, struct sip_request *req, const char *name);
+static char get_sdp_line(int *start, int stop, struct sip_request *req, const char **value);
 static int find_sdp(struct sip_request *req);
 static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action);
+static int process_sdp_o(const char *o, struct sip_pvt *p);
+static int process_sdp_c(const char *c, struct ast_hostent *hp);
+static int process_sdp_a_sendonly(const char *a, int *sendonly);
+static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newaudiortp, int *last_rtpmap_codec);
+static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newvideortp, int *last_rtpmap_codec);
+static int process_sdp_a_text(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newtextrtp, char *red_fmtp, int *red_num_gen, int *red_data_pt, int *last_rtpmap_codec);
+static int process_sdp_a_image(const char *a, struct sip_pvt *p);
 static void add_codec_to_sdp(const struct sip_pvt *p, format_t codec,
 			     struct ast_str **m_buf, struct ast_str **a_buf,
 			     int debug, int *min_packet_size);
@@ -7128,12 +7135,27 @@ static const char *get_sdp_iterate(int *start, struct sip_request *req, const ch
 	return "";
 }
 
-/*! \brief Get a line from an SDP message body */
-static const char *get_sdp(struct sip_request *req, const char *name)
+/*! \brief Fetches the next valid SDP line between the 'start' line
+ * and the 'stop' line. Returns the type ('a', 'c', ...) and 
+ * matching line in reference 'start' is updated with the next line number.
+ */
+static char get_sdp_line(int *start, int stop, struct sip_request *req, const char **value)
 {
-	int dummy = 0;
+	char type = '\0';
+	const char *line = NULL;
+
+	if (stop > req->sdp_end || stop < req->sdp_start) stop = req->sdp_end;
+
+	while (*start < stop) {
+		line = REQ_OFFSET_TO_STR(req, line[(*start)++]);
+		if (line[1] == '=') {
+			type = line[0];
+			*value = ast_skip_blanks(line + 2);
+			break;
+		}
+	}
 
-	return get_sdp_iterate(&dummy, req, name);
+	return type;
 }
 
 /*! \brief Get a specific line from the message body */
@@ -8348,60 +8370,63 @@ static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_ty
 */
 static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action)
 {
-	const char *m;		/* SDP media offer */
-	const char *c;
-	const char *a;
-	const char *o;		/* Pointer to o= line */
-	char *o_copy;		/* Copy of o= line */
-	char *token;
-	char host[258];
+	/* Iterators for SDP parsing */
+	int start = req->sdp_start;
+	int next = start;
+	int iterator = start;
+
+	/* Temporary vars for SDP parsing */
+	char type = '\0';
+	const char *value = NULL;
+	const char *m = NULL;           /* SDP media offer */
+	const char *nextm = NULL;
 	int len = -1;
-	int portno = -1;		/*!< RTP Audio port number */
-	int vportno = -1;		/*!< RTP Video port number */
+
+	/* Host information */
+	struct ast_hostent sessionhp;
+	struct ast_hostent audiohp;
+	struct ast_hostent videohp;
+	struct ast_hostent texthp;
+	struct hostent *hp = NULL;	/*!< RTP Audio host IP */
+	struct hostent *vhp = NULL;	/*!< RTP video host IP */
+	struct hostent *thp = NULL;	/*!< RTP text host IP */
+ 	int portno = -1;		/*!< RTP Audio port number */
+ 	int vportno = -1;		/*!< RTP Video port number */
 	int tportno = -1;		/*!< RTP Text port number */
-	int udptlportno = -1;
-	char s[256];
-	int old = 0;
+	int udptlportno = -1;		/*!< UDPTL Image port number */
+	struct sockaddr_in sin;		/*!< media socket address */
+	struct sockaddr_in vsin;	/*!< video socket address */
+	struct sockaddr_in isin;	/*!< image socket address */
+	struct sockaddr_in tsin;	/*!< text socket address */
 
 	/* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */	
 	format_t peercapability = 0, vpeercapability = 0, tpeercapability = 0;
 	int peernoncodeccapability = 0, vpeernoncodeccapability = 0, tpeernoncodeccapability = 0;
-	struct sockaddr_in sin;		/*!< media socket address */
-	struct sockaddr_in vsin;	/*!< Video socket address */
-	struct sockaddr_in tsin;	/*!< Text socket address */
 
-	const char *codecs;
-	struct hostent *hp;		/*!< RTP Audio host IP */
-	struct hostent *vhp = NULL;	/*!< RTP video host IP */
-	struct hostent *thp = NULL;	/*!< RTP text host IP */
-	struct ast_hostent audiohp;
-	struct ast_hostent videohp;
-	struct ast_hostent texthp;
-	int codec;
-	int destiterator = 0;
-	int iterator;
-	int sendonly = -1;
-	int numberofports;
 	struct ast_rtp_codecs newaudiortp, newvideortp, newtextrtp;
 	format_t newjointcapability;				/* Negotiated capability */
 	format_t newpeercapability;
 	int newnoncodeccapability;
+
+	const char *codecs;
+	int codec;
+
+	/* Others */
+	int sendonly = -1;
+	int vsendonly = -1;
+	int numberofports;
 	int numberofmediastreams = 0;
+	int last_rtpmap_codec = 0;
+	int red_data_pt[10];		/* For T.140 red */
+	int red_num_gen = 0;		/* For T.140 red */
+	char red_fmtp[100] = "empty";	/* For T.140 red */
 	int debug = sip_debug_test_pvt(p);
-		
-	int found_rtpmap_codecs[SDP_MAX_RTPMAP_CODECS];
-	int last_rtpmap_codec=0;
 
+	/* START UNKNOWN */
 	char buf[SIPBUFSIZE];
-	int64_t rua_version;
-	
-	int red_data_pt[10];
-	int red_num_gen = 0;
-	int red_pt = 0;
-
-	char *red_cp; 				/* For T.140 red */
-	char red_fmtp[100] = "empty";		/* For T.140 red */
+	/* END UNKNOWN */
 
+	/* Initial check */
 	if (!p->rtp) {
 		ast_log(LOG_ERROR, "Got SDP but have no RTP session allocated.\n");
 		return -1;
@@ -8417,102 +8442,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 
 	memset(p->offered_media, 0, sizeof(p->offered_media));
 
-	/* Store the SDP version number of remote UA. This will allow us to
-	distinguish between session modifications and session refreshes. If
-	the remote UA does not send an incremented SDP version number in a
-	subsequent RE-INVITE then that means its not changing media session.
-	The RE-INVITE may have been sent to update connected party, remote
-	target or to refresh the session (Session-Timers).  Asterisk must not
-	change media session and increment its own version number in answer
-	SDP in this case. */
-	
-	o = get_sdp(req, "o");
-	if (ast_strlen_zero(o)) {
-		ast_log(LOG_WARNING, "SDP syntax error. SDP without an o= line\n");
-		return -1;
-	}
-
-	o_copy = ast_strdupa(o);
-	token = strsep(&o_copy, " ");  /* Skip username   */
-	if (!o_copy) {
-		ast_log(LOG_WARNING, "SDP syntax error in o= line username\n");
-		return -1;
-	}
-	token = strsep(&o_copy, " ");  /* Skip session-id */
-	if (!o_copy) {
-		ast_log(LOG_WARNING, "SDP syntax error in o= line session-id\n");
-		return -1;
-	}
-	token = strsep(&o_copy, " ");  /* Version         */
-	if (!o_copy) {
-		ast_log(LOG_WARNING, "SDP syntax error in o= line\n");
-		return -1;
-	}
-	if (!sscanf(token, "%30" SCNd64, &rua_version)) {
-		ast_log(LOG_WARNING, "SDP syntax error in o= line version\n");
-		return -1;
-	}
-
-	/* we need to check the SDP version number the other end sent us;
-	 * our rules for deciding what to accept are a bit complex.
-	 *
-	 * 1) if 'ignoresdpversion' has been set for this dialog, then
-	 *    we will just accept whatever they sent and assume it is
-	 *    a modification of the session, even if it is not
-	 * 2) otherwise, if this is the first SDP we've seen from them
-	 *    we accept it
-	 * 3) otherwise, if the new SDP version number is higher than the
-	 *    old one, we accept it
-	 * 4) otherwise, if this SDP is in response to us requesting a switch
-	 *    to T.38, we accept the SDP, but also generate a warning message
-	 *    that this peer should have the 'ignoresdpversion' option set,
-	 *    because it is not following the SDP offer/answer RFC; if we did
-	 *    not request a switch to T.38, then we stop parsing the SDP, as it
-	 *    has not changed from the previous version
-	 */
-
-	if (ast_test_flag(&p->flags[1], SIP_PAGE2_IGNORESDPVERSION) ||
-	    (p->sessionversion_remote < 0) ||
-	    (p->sessionversion_remote < rua_version)) {
-		p->sessionversion_remote = rua_version;
-		p->session_modify = TRUE;
-	} else {
-		if (p->t38.state == T38_LOCAL_REINVITE) {
-			p->sessionversion_remote = rua_version;
-			p->session_modify = TRUE;
-			ast_log(LOG_WARNING, "Call %s responded to our T.38 reinvite without changing SDP version; 'ignoresdpversion' should be set for this peer.\n", p->callid);
-		} else {
-			p->session_modify = FALSE;
-			ast_debug(2, "Call %s responded to our reinvite without changing SDP version; ignoring SDP.\n", p->callid);
-			return 0;
-		}
-	}
-
-	/* Try to find first media stream */
-	m = get_sdp(req, "m");
-	destiterator = req->sdp_start;
-	c = get_sdp_iterate(&destiterator, req, "c");
-	if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
-		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, &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 */
-	thp = hp;	/* Copy to text address as default too */
-	
-	iterator = req->sdp_start;
 	/* default: novideo and notext set */
 	p->novideo = TRUE;
 	p->notext = TRUE;
@@ -8525,22 +8455,74 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 		ast_rtp_codecs_payloads_clear(&newtextrtp, NULL);
 	}
 
-	/* Find media streams in this SDP offer */
-	while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
-		int x;
+	/* Scan for the first media stream (m=) line to limit scanning of globals */
+	nextm = get_sdp_iterate(&next, req, "m");
+	if (ast_strlen_zero(nextm)) {
+		ast_log(LOG_WARNING, "Insufficient information for SDP (m= not found)\n");
+ 		return -1;
+ 	}
+
+	/* Scan session level SDP parameters (lines before first media stream) */
+	while ((type = get_sdp_line(&iterator, next - 1, req, &value)) != '\0') {
+		int processed = FALSE;
+		switch (type) {
+		case 'o':
+			if (!process_sdp_o(value, p))
+				return -1;
+			break;
+		case 'c':
+			if (process_sdp_c(value, &sessionhp)) {
+				processed = TRUE;
+				hp = &sessionhp.hp;
+				vhp = hp;
+				thp = hp;
+			}
+			break;
+		case 'a':
+			if (process_sdp_a_sendonly(value, &sendonly)) {
+				processed = TRUE;
+				vsendonly = sendonly;
+			}
+			else if (process_sdp_a_audio(value, p, &newaudiortp, &last_rtpmap_codec))
+				processed = TRUE;
+			else if (process_sdp_a_video(value, p, &newvideortp, &last_rtpmap_codec))
+				processed = TRUE;
+			else if (process_sdp_a_text(value, p, &newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec))
+				processed = TRUE;
+			else if (process_sdp_a_image(value, p))
+				processed = TRUE;
+			break;
+		}
+
+		if (option_debug > 2)
+			ast_log(LOG_DEBUG, "Processing session-level SDP %c=%s... %s\n", type, value, (processed == TRUE)? "OK." : "UNSUPPORTED.");
+ 	}
+
+
+
+	/* Scan media stream (m=) specific parameters loop */
+	while (!ast_strlen_zero(nextm)) {
 		int audio = FALSE;
 		int video = FALSE;
+		int image = FALSE;
 		int text = FALSE;
+		int x;
 
 		numberofports = 1;
 		len = -1;
+		start = next;
+		m = nextm;
+		iterator = next;
+		nextm = get_sdp_iterate(&next, req, "m");
+
+		/* Search for audio media definition */
 		if ((sscanf(m, "audio %30d/%30d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
 		    (sscanf(m, "audio %30d RTP/AVP %n", &x, &len) == 1 && len > 0)) {
 			audio = TRUE;
 			p->offered_media[SDP_AUDIO].offered = TRUE;
 			numberofmediastreams++;
-			/* Found audio stream in this media definition */
 			portno = x;
+
 			/* Scan through the RTP payload types specified in a "m=" line: */
 			codecs = m + len;
 			ast_copy_string(p->offered_media[SDP_AUDIO].codecs, codecs, sizeof(p->offered_media[SDP_AUDIO].codecs));
@@ -8554,13 +8536,15 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 				
 				ast_rtp_codecs_payloads_set_m_type(&newaudiortp, NULL, codec);
 			}
+		/* Search for video media definition */
 		} else if ((sscanf(m, "video %30d/%30d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
-		    (sscanf(m, "video %30d RTP/AVP %n", &x, &len) == 1 && len >= 0)) {
+			   (sscanf(m, "video %30d RTP/AVP %n", &x, &len) == 1 && len >= 0)) {
 			video = TRUE;
 			p->novideo = FALSE;
 			p->offered_media[SDP_VIDEO].offered = TRUE;
 			numberofmediastreams++;
 			vportno = x;
+
 			/* Scan through the RTP payload types specified in a "m=" line: */
 			codecs = m + len;
 			ast_copy_string(p->offered_media[SDP_VIDEO].codecs, codecs, sizeof(p->offered_media[SDP_VIDEO].codecs));
@@ -8573,13 +8557,15 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 					ast_verbose("Found RTP video format %d\n", codec);
 				ast_rtp_codecs_payloads_set_m_type(&newvideortp, NULL, codec);
 			}
+		/* Search for text media definition */
 		} else if ((sscanf(m, "text %30d/%30d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
-		    (sscanf(m, "text %30d RTP/AVP %n", &x, &len) == 1 && len > 0)) {
+			   (sscanf(m, "text %30d RTP/AVP %n", &x, &len) == 1 && len > 0)) {
 			text = TRUE;
-			p->offered_media[SDP_TEXT].offered = TRUE;
 			p->notext = FALSE;
+			p->offered_media[SDP_TEXT].offered = TRUE;
 			numberofmediastreams++;
 			tportno = x;
+
 			/* Scan through the RTP payload types specified in a "m=" line: */
 			codecs = m + len;
 			ast_copy_string(p->offered_media[SDP_TEXT].codecs, codecs, sizeof(p->offered_media[SDP_TEXT].codecs));
@@ -8592,46 +8578,105 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 					ast_verbose("Found RTP text format %d\n", codec);
 				ast_rtp_codecs_payloads_set_m_type(&newtextrtp, NULL, codec);
 			}
-		} else if (p->udptl && ( (sscanf(m, "image %30d udptl t38%n", &x, &len) == 1 && len > 0) ||
-			(sscanf(m, "image %30d UDPTL t38%n", &x, &len) == 1 && len > 0) )) {
+		/* Search for image media definition */
+		} else if (p->udptl && ((sscanf(m, "image %30d udptl t38%n", &x, &len) == 1 && len > 0) ||
+					(sscanf(m, "image %30d UDPTL t38%n", &x, &len) == 1 && len > 0) )) {
+			image = TRUE;
 			if (debug)
 				ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid);
 			p->offered_media[SDP_IMAGE].offered = TRUE;
 			udptlportno = x;
 			numberofmediastreams++;
-		} else
+
+			if (p->t38.state != T38_ENABLED) {
+				memset(&p->t38.their_parms, 0, sizeof(p->t38.their_parms));
+
+				/* Remote party offers T38, we need to update state */
+				if ((t38action == SDP_T38_ACCEPT) &&
+				    (p->t38.state == T38_LOCAL_REINVITE)) {
+					change_t38_state(p, T38_ENABLED);
+				} else if ((t38action == SDP_T38_INITIATE) &&
+					   p->owner && p->lastinvite) {
+					change_t38_state(p, T38_PEER_REINVITE); /* T38 Offered in re-invite from remote party */
+				}
+			}
+		} else {
 			ast_log(LOG_WARNING, "Unsupported SDP media type in offer: %s\n", m);
+			continue;
+		}
+
+		/* Check for number of ports */
 		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 */
+
+		/* Media stream specific parameters */
+		while ((type = get_sdp_line(&iterator, next - 1, req, &value)) != '\0') {
+			int processed = FALSE;
+
+			switch (type) {
+			case '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);
-						return -2;
+					if (process_sdp_c(value, &audiohp)) {
+						processed = TRUE;
+						hp = &audiohp.hp;
 					}
 				} else if (video) {
-					if (!(vhp = ast_gethostbyname(host, &videohp))) {
-						ast_log(LOG_WARNING, "Unable to lookup RTP video host in secondary c= line, '%s'\n", c);
-						return -2;
+					if (process_sdp_c(value, &videohp)) {
+						processed = TRUE;
+						vhp = &videohp.hp;
 					}
 				} else if (text) {
-					if (!(thp = ast_gethostbyname(host, &texthp))) {
-						ast_log(LOG_WARNING, "Unable to lookup RTP text host in secondary c= line, '%s'\n", c);
-						return -2;
+					if (process_sdp_c(value, &texthp)) {
+						processed = TRUE;
+						thp = &texthp.hp;
 					}
 				}
+				break;
+			case 'a':
+				/* Audio specific scanning */
+				if (audio) {
+					if (process_sdp_a_sendonly(value, &sendonly))
+						processed = TRUE;
+					else if (process_sdp_a_audio(value, p, &newaudiortp, &last_rtpmap_codec))
+						processed = TRUE;
+				}
+				/* Video specific scanning */
+				else if (video) {
+					if (process_sdp_a_sendonly(value, &vsendonly))
+						processed = TRUE;
+					else if (process_sdp_a_video(value, p, &newvideortp, &last_rtpmap_codec))
+						processed = TRUE;
+				}
+				/* Text (T.140) specific scanning */
+				else if (text) {
+					if (process_sdp_a_text(value, p, &newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec))
+						processed = TRUE;
+				}
+				/* Image (T.38 FAX) specific scanning */
+				else if (image) {
+					if (process_sdp_a_image(value, p))
+						processed = TRUE;
+				}
+				break;
 			}
 
+			if (option_debug > 2)
+				ast_log(LOG_DEBUG, "Processing media-level (%s) SDP %c=%s... %s\n",
+						(audio == TRUE)? "audio" : (video == TRUE)? "video" : "image",
+						type, value,
+						(processed == TRUE)? "OK." : "UNSUPPORTED.");
 		}
 	}
+
+
+	/* Sanity checks */
+	if (!hp) {
+		ast_log(LOG_WARNING, "Insufficient information in SDP (c=)...\n");
+		return -1;
+	}
+
 	if (portno == -1 && vportno == -1 && udptlportno == -1  && tportno == -1)
 		/* No acceptable offer found in SDP  - we have no ports */
 		/* Do not change RTP or VRTP if this is a re-invite */
@@ -8641,374 +8686,11 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 		/* We have too many fax, audio and/or video and/or text 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;
-	tsin.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));
-	if (thp)
-		memcpy(&tsin.sin_addr, thp->h_addr, sizeof(tsin.sin_addr));
-
-	/* Setup UDPTL port number */
-	if (p->udptl) {
-		if (udptlportno > 0) {
-			sin.sin_port = htons(udptlportno);
-			if (ast_test_flag(&p->flags[1], SIP_PAGE2_SYMMETRICRTP) && ast_test_flag(&p->flags[1], SIP_PAGE2_UDPTL_DESTINATION)) {
-				struct sockaddr_in remote_address = { 0, };
-				ast_rtp_instance_get_remote_address(p->rtp, &remote_address);
-				if (remote_address.sin_addr.s_addr) {
-					memcpy(&sin, &remote_address, sizeof(sin));
-					if (debug) {
-						ast_log(LOG_DEBUG, "Peer T.38 UDPTL is set behind NAT and with destination, destination address now %s\n", ast_inet_ntoa(sin.sin_addr));
-					}
-				}
-			}
-			ast_udptl_set_peer(p->udptl, &sin);
-			if (debug)
-				ast_debug(1, "Peer T.38 UDPTL is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
-		} else {
-			ast_udptl_stop(p->udptl);
-			if (debug)
-				ast_debug(1, "Peer doesn't provide T.38 UDPTL\n");
-		}
-	}
-
-		
-	if (p->rtp) {
-		if (portno > 0) {
-			sin.sin_port = htons(portno);
-			ast_rtp_instance_set_remote_address(p->rtp, &sin);
-			if (debug)
-				ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
-		} else {
-			if (udptlportno > 0) {
-				if (debug)
-					ast_verbose("Got T.38 Re-invite without audio. Keeping RTP active during T.38 session. Callid %s\n", p->callid);
-			} else {
-				ast_rtp_instance_stop(p->rtp);
-				if (debug)
-					ast_verbose("Peer doesn't provide audio. Callid %s\n", p->callid);
-			}
-		}
-	}
-	/* Setup video port number, assumes we have audio */
-	if (vportno != -1)
-		vsin.sin_port = htons(vportno);
-
-	/* Setup text port number, assumes we have audio */
-	if (tportno != -1)
-		tsin.sin_port = htons(tportno);
-
-	/* Next, scan through each "a=xxxx:" 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[128];
-		char fmtp_string[64];
-		unsigned int sample_rate;
-
-		if (option_debug > 1) {
-			int breakout = FALSE;
-
-			/* If we're debugging, check for unsupported sdp options */
-			if (!strncasecmp(a, "rtcp:", (size_t) 5)) {
-				if (debug)
-					ast_verbose("Got unsupported a:rtcp in SDP offer \n");
-				breakout = TRUE;
-			} else if (!strncasecmp(a, "framerate:", (size_t) 10)) {
-				/* Video stuff:  Not supported */
-				if (debug)
-					ast_verbose("Got unsupported a:framerate in SDP offer \n");
-				breakout = TRUE;
-			} else if (!strncasecmp(a, "maxprate:", (size_t) 9)) {
-				/* Video stuff:  Not supported */
-				if (debug)
-					ast_verbose("Got unsupported a:maxprate in SDP offer \n");
-				breakout = TRUE;
-			} 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");
-				breakout = TRUE;
-			}
-			if (breakout)	/* We have a match, skip to next header */
-				continue;
-		}
-
-		if (!strcasecmp(a, "sendonly")) {
-			if (sendonly == -1)
-				sendonly = 1;
-			continue;
-		}
-
-		if (!strcasecmp(a, "inactive")) {
-			if (sendonly == -1)
-				sendonly = 2;
-			continue;
-		}
-
-		if (!strcasecmp(a, "sendrecv")) {
-			if (sendonly == -1)
-				sendonly = 0;
-			continue;
-		}
-
-		if (!strncasecmp(a, "ptime", 5)) {
-			char *tmp = strrchr(a, ':');
-			long int framing = 0;
-
-			if (tmp) {
-				tmp++;
-				framing = strtol(tmp, NULL, 10);
-				if (framing == LONG_MIN || framing == LONG_MAX) {
-					framing = 0;
-					ast_debug(1, "Can't read framing from SDP: %s\n", a);
-				}
-			}
-			if (framing && p->autoframing) {
-				struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(p->rtp)->pref;
-				int codec_n;
-				for (codec_n = 0; codec_n < AST_RTP_MAX_PT; codec_n++) {
-					struct ast_rtp_payload_type format = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(p->rtp), codec_n);
-					if (!format.asterisk_format || !format.code)	/* non-codec or not found */
-						continue;
-					if (option_debug)
-						ast_log(LOG_DEBUG, "Setting framing for %s to %ld\n", ast_getformatname(format.code), framing);
-					ast_codec_pref_setsize(pref, format.code, framing);
-				}
-				ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, pref);
-			}
-			continue;
-		}
-
-		if (!strncmp(a, red_fmtp, strlen(red_fmtp))) {
-			/* count numbers of generations in fmtp */
-			red_cp = &red_fmtp[strlen(red_fmtp)];
-			strncpy(red_fmtp, a, 100);
-
-			sscanf(red_cp, "%30u", &red_data_pt[red_num_gen]);
-			red_cp = strtok(red_cp, "/");
-			while (red_cp && red_num_gen++ < AST_RED_MAX_GENERATION) {
-				sscanf(red_cp, "%30u", &red_data_pt[red_num_gen]);
-				red_cp = strtok(NULL, "/");
-			}
-			red_cp = red_fmtp;
-			continue;
-		}
-
-		if (sscanf(a, "fmtp: %30u %63s", &codec, fmtp_string) == 2) {
-			struct ast_rtp_payload_type payload;
-			unsigned int handled = 0;
-
-			payload = ast_rtp_codecs_payload_lookup(&newaudiortp, codec);
-			if (!payload.code) {
-				/* it wasn't found, try the video rtp */
-				payload = ast_rtp_codecs_payload_lookup(&newvideortp, codec);
-			}
-			if (payload.code && payload.asterisk_format) {
-				unsigned int bit_rate;
-
-				switch (payload.code) {
-				case AST_FORMAT_SIREN7:
-					if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
-						if (bit_rate != 32000) {
-							ast_log(LOG_WARNING, "Got Siren7 offer at %d bps, but only 32000 bps supported; ignoring.\n", bit_rate);
-							ast_rtp_codecs_payloads_unset(&newaudiortp, NULL, codec);
-						} else {
-							handled = 1;
-						}
-					}
-					break;
-				case AST_FORMAT_SIREN14:
-					if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
-						if (bit_rate != 48000) {
-							ast_log(LOG_WARNING, "Got Siren14 offer at %d bps, but only 48000 bps supported; ignoring.\n", bit_rate);
-							ast_rtp_codecs_payloads_unset(&newaudiortp, NULL, codec);
-						} else {
-							handled = 1;
-						}
-					}
-					break;
-				}
-			}
-
-			if (!handled) {
-				ast_debug(1, "Got unsupported a:%s in SDP offer\n", a);
-			}
-			continue;
-		}
-
-		if (sscanf(a, "rtpmap: %30u %127[^/]/%30u", &codec, mimeSubtype, &sample_rate) == 3) {
-			/* We have a rtpmap to handle */
-
-			if (last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
-				/* Note: should really look at the '#chans' params too */
-				/* Note: This should all be done in the context of the m= above */
-				if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)) {         /* Video */
-					if (ast_rtp_codecs_payloads_set_rtpmap_type_rate(&newvideortp, NULL, codec, "video", mimeSubtype, 0, sample_rate) != -1) {
-						if (debug)
-							ast_verbose("Found video description format %s for ID %d\n", mimeSubtype, codec);
-						found_rtpmap_codecs[last_rtpmap_codec] = codec;
-						last_rtpmap_codec++;
-					} else {
-						ast_rtp_codecs_payloads_unset(&newvideortp, NULL, codec);
-						if (debug)
-							ast_verbose("Found unknown media description format %s for ID %d\n", mimeSubtype, codec);
-					}
-				} else if (!strncasecmp(mimeSubtype, "T140", 4)) { /* Text */
-					if (p->trtp) {
-						/* ast_verbose("Adding t140 mimeSubtype to textrtp struct\n"); */
-						ast_rtp_codecs_payloads_set_rtpmap_type_rate(&newtextrtp, NULL, codec, "text", mimeSubtype, 0, sample_rate);
-					}
-				} else if (!strncasecmp(mimeSubtype, "RED", 3)) { /* Text with Redudancy */
-					if (p->trtp) {
-						ast_rtp_codecs_payloads_set_rtpmap_type_rate(&newtextrtp, NULL, codec, "text", mimeSubtype, 0, sample_rate);
-						red_pt = codec;
-						sprintf(red_fmtp, "fmtp:%d ", red_pt);
-
-						if (debug)
-							ast_verbose("RED submimetype has payload type: %d\n", red_pt);
-					}
-				} else {                                          /* Must be audio?? */
-					if (ast_rtp_codecs_payloads_set_rtpmap_type_rate(&newaudiortp, NULL, codec, "audio", mimeSubtype,
-											ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0, sample_rate) != -1) {
-						if (debug)
-							ast_verbose("Found audio description format %s for ID %d\n", mimeSubtype, codec);
-						found_rtpmap_codecs[last_rtpmap_codec] = codec;
-						last_rtpmap_codec++;
-					} else {
-						ast_rtp_codecs_payloads_unset(&newaudiortp, NULL, codec);
-						if (debug)
-							ast_verbose("Found unknown media description format %s for ID %d\n", mimeSubtype, codec);
-					}
-				}
-			} else {
-				if (debug)
-					ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec);
-			}
-
-		}
-	}
-	
-	if (udptlportno != -1) {
-		if (p->t38.state != T38_ENABLED) {
-			int found = 0, x;
-		
-			old = 0;
-			memset(&p->t38.their_parms, 0, sizeof(p->t38.their_parms));
-		
-			/* Scan trough the a= lines for T38 attributes and set apropriate fileds */
-			iterator = req->sdp_start;
-			while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
-				if ((sscanf(a, "T38FaxMaxBuffer:%30d", &x) == 1)) {
-					found = 1;
-					ast_debug(3, "MaxBufferSize:%d\n", x);
-				} else if ((sscanf(a, "T38MaxBitRate:%30d", &x) == 1) || (sscanf(a, "T38FaxMaxRate:%30d", &x) == 1)) {
-					found = 1;
-					ast_debug(3, "T38MaxBitRate: %d\n", x);
-					switch (x) {
-					case 14400:
-						p->t38.their_parms.rate = AST_T38_RATE_14400;
-						break;
-					case 12000:
-						p->t38.their_parms.rate = AST_T38_RATE_12000;
-						break;
-					case 9600:
-						p->t38.their_parms.rate = AST_T38_RATE_9600;
-						break;
-					case 7200:
-						p->t38.their_parms.rate = AST_T38_RATE_7200;
-						break;
-					case 4800:
-						p->t38.their_parms.rate = AST_T38_RATE_4800;
-						break;
-					case 2400:
-						p->t38.their_parms.rate = AST_T38_RATE_2400;
-						break;
-					}
-				} else if ((sscanf(a, "T38FaxVersion:%30d", &x) == 1)) {
-					found = 1;
-					ast_debug(3, "FaxVersion: %d\n", x);
-					p->t38.their_parms.version = x;
-				} else if ((sscanf(a, "T38FaxMaxDatagram:%30d", &x) == 1) || (sscanf(a, "T38MaxDatagram:%30d", &x) == 1)) {
-					/* override the supplied value if the configuration requests it */
-					if (p->t38_maxdatagram > x) {
-						ast_debug(1, "Overriding T38FaxMaxDatagram '%d' with '%d'\n", x, p->t38_maxdatagram);
-						x = p->t38_maxdatagram;
-					}
-					found = 1;
-					ast_debug(3, "FaxMaxDatagram: %d\n", x);
-					ast_udptl_set_far_max_datagram(p->udptl, x);
-				} else if ((strncmp(a, "T38FaxFillBitRemoval", 20) == 0)) {
-					found = 1;
-					if (sscanf(a, "T38FaxFillBitRemoval:%30d", &x) == 1) {
-						ast_debug(3, "FillBitRemoval: %d\n", x);
-						if (x == 1) {
-							p->t38.their_parms.fill_bit_removal = TRUE;
-						}
-					} else {
-						ast_debug(3, "FillBitRemoval\n");
-						p->t38.their_parms.fill_bit_removal = TRUE;
-					}
-				} else if ((strncmp(a, "T38FaxTranscodingMMR", 20) == 0)) {
-					found = 1;
-					if (sscanf(a, "T38FaxTranscodingMMR:%30d", &x) == 1) {
-						ast_debug(3, "Transcoding MMR: %d\n", x);
-						if (x == 1) {
-							p->t38.their_parms.transcoding_mmr = TRUE;
-						}
-					} else {
-						ast_debug(3, "Transcoding MMR\n");
-						p->t38.their_parms.transcoding_mmr = TRUE;
-					}
-				} else if ((strncmp(a, "T38FaxTranscodingJBIG", 21) == 0)) {
-					found = 1;
-					if (sscanf(a, "T38FaxTranscodingJBIG:%30d", &x) == 1) {
-						ast_debug(3, "Transcoding JBIG: %d\n", x);
-						if (x == 1) {
-							p->t38.their_parms.transcoding_jbig = TRUE;
-						}
-					} else {
-						ast_debug(3, "Transcoding JBIG\n");
-						p->t38.their_parms.transcoding_jbig = TRUE;
-					}
-				} else if ((sscanf(a, "T38FaxRateManagement:%255s", s) == 1)) {
-					found = 1;
-					ast_debug(3, "RateManagement: %s\n", s);
-					if (!strcasecmp(s, "localTCF"))
-						p->t38.their_parms.rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
-					else if (!strcasecmp(s, "transferredTCF"))
-						p->t38.their_parms.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
-				} else if ((sscanf(a, "T38FaxUdpEC:%255s", s) == 1)) {
-					found = 1;
-					ast_debug(3, "UDP EC: %s\n", s);
-					if (!strcasecmp(s, "t38UDPRedundancy")) {
-						ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY);
-					} else if (!strcasecmp(s, "t38UDPFEC")) {
-						ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_FEC);
-					} else {
-						ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE);
-					}
-				}
-			}
-
-			/* Remote party offers T38, we need to update state */
-			if ((t38action == SDP_T38_ACCEPT) &&
-			    (p->t38.state == T38_LOCAL_REINVITE)) {
-				change_t38_state(p, T38_ENABLED);
-			} else if ((t38action == SDP_T38_INITIATE) &&
-				   p->owner && p->lastinvite) {
-				change_t38_state(p, T38_PEER_REINVITE); /* T38 Offered in re-invite from remote party */
-			}
-		}
-	} else {
+	if (udptlportno == -1) {
 		change_t38_state(p, T38_DISABLED);
 	}
 
+
 	/* Now gather all of the codecs that we are asked for: */
 	ast_rtp_codecs_payload_formats(&newaudiortp, &peercapability, &peernoncodeccapability);
 	ast_rtp_codecs_payload_formats(&newvideortp, &vpeercapability, &vpeernoncodeccapability);
@@ -9029,7 +8711,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 			    ast_getformatname_multiple(s4, SIPBUFSIZE, tpeercapability),
 			    ast_getformatname_multiple(s5, SIPBUFSIZE, newjointcapability));
 	}
-
 	if (debug) {
 		struct ast_str *s1 = ast_str_alloca(SIPBUFSIZE);
 		struct ast_str *s2 = ast_str_alloca(SIPBUFSIZE);
@@ -9090,25 +8771,79 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 		}
 	}
 
-	/* Setup audio port number */
-	if (p->rtp && sin.sin_port) {
-		ast_rtp_instance_set_remote_address(p->rtp, &sin);
-		if (debug)
-			ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+	/* Setup audio address and port */
+	if (p->rtp) {
+		if (portno > 0) {
+			sin.sin_family = AF_INET;
+			sin.sin_port = htons(portno);
+			memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+			ast_rtp_instance_set_remote_address(p->rtp, &sin);
+			if (debug)
+				ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+		} else if (udptlportno > 0) {
+			if (debug)
+				ast_verbose("Got T.38 Re-invite without audio. Keeping RTP active during T.38 session.\n");
+		} else {
+			ast_rtp_instance_stop(p->rtp);
+			if (debug)
+				ast_verbose("Peer doesn't provide audio\n");
+		}
 	}
 
-	/* Setup video port number */
-	if (p->vrtp && vsin.sin_port) {
-		ast_rtp_instance_set_remote_address(p->vrtp, &vsin);
-		if (debug)
-			ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(vsin.sin_addr), ntohs(vsin.sin_port));
+	/* Setup video address and port */
+	if (p->vrtp) {
+		if (vportno > 0) {
+			vsin.sin_family = AF_INET;
+			vsin.sin_port = htons(vportno);
+			memcpy(&vsin.sin_addr, vhp->h_addr, sizeof(vsin.sin_addr));
+			ast_rtp_instance_set_remote_address(p->vrtp, &vsin);
+			if (debug) 
+				ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(vsin.sin_addr), ntohs(vsin.sin_port));
+		} else {
+			ast_rtp_instance_stop(p->vrtp);
+			if (debug)
+				ast_verbose("Peer doesn't provide video\n");
+		}
 	}
 
-	/* Setup text port number */
-	if (p->trtp && tsin.sin_port) {
-		ast_rtp_instance_set_remote_address(p->trtp, &tsin);
-		if (debug)
-			ast_verbose("Peer text RTP is at port %s:%d\n", ast_inet_ntoa(tsin.sin_addr), ntohs(tsin.sin_port));
+	/* Setup text address and port */
+	if (p->trtp) {
+		if (tportno > 0) {
+			tsin.sin_family = AF_INET;
+			tsin.sin_port = htons(tportno);
+			memcpy(&tsin.sin_addr, thp->h_addr, sizeof(tsin.sin_addr));
+			ast_rtp_instance_set_remote_address(p->trtp, &tsin);
+			if (debug) 
+				ast_verbose("Peer T.140 RTP is at port %s:%d\n", ast_inet_ntoa(vsin.sin_addr), ntohs(vsin.sin_port));
+		} else {
+			ast_rtp_instance_stop(p->trtp);
+			if (debug)
+				ast_verbose("Peer doesn't provide T.140\n");
+		}
+	}
+	/* Setup image address and port */
+	if (p->udptl) {
+		if (udptlportno > 0) {
+			isin.sin_family = AF_INET;
+			isin.sin_port = htons(udptlportno);
+			if (ast_test_flag(&p->flags[1], SIP_PAGE2_SYMMETRICRTP) && ast_test_flag(&p->flags[1], SIP_PAGE2_UDPTL_DESTINATION)) {
+				struct sockaddr_in remote_address = { 0, };
+				ast_rtp_instance_get_remote_address(p->rtp, &remote_address);
+				if (remote_address.sin_addr.s_addr) {
+					memcpy(&isin, &remote_address, sizeof(isin));
+					if (debug) {
+						ast_log(LOG_DEBUG, "Peer T.38 UDPTL is set behind NAT and with destination, destination address now %s\n", ast_inet_ntoa(isin.sin_addr));
+					}
+				}
+			}
+			ast_udptl_set_peer(p->udptl, &isin);
+			if (debug)
+				ast_debug(1,"Peer T.38 UDPTL is at port %s:%d\n", ast_inet_ntoa(isin.sin_addr), ntohs(isin.sin_port));
+		} else {
+			ast_udptl_stop(p->udptl);
+			if (debug)
+				ast_debug(1, "Peer doesn't provide T.38 UDPTL\n");
+		}
 	}
 
 	/* Ok, we're going with this offer */
@@ -9180,6 +8915,396 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 	return 0;
 }
 
+static int process_sdp_o(const char *o, struct sip_pvt *p)
+{
+	char *o_copy;
+	char *token;
+	int64_t rua_version;
+
+	/* Store the SDP version number of remote UA. This will allow us to
+	distinguish between session modifications and session refreshes. If
+	the remote UA does not send an incremented SDP version number in a
+	subsequent RE-INVITE then that means its not changing media session.
+	The RE-INVITE may have been sent to update connected party, remote
+	target or to refresh the session (Session-Timers).  Asterisk must not
+	change media session and increment its own version number in answer
+	SDP in this case. */
+
+	if (ast_strlen_zero(o)) {
+		ast_log(LOG_WARNING, "SDP syntax error. SDP without an o= line\n");
+		return FALSE;
+	}
+
+	o_copy = ast_strdupa(o);
+	token = strsep(&o_copy, " ");  /* Skip username   */
+	if (!o_copy) {
+		ast_log(LOG_WARNING, "SDP syntax error in o= line username\n");
+		return FALSE;
+	}
+	token = strsep(&o_copy, " ");  /* Skip session-id */
+	if (!o_copy) {
+		ast_log(LOG_WARNING, "SDP syntax error in o= line session-id\n");
+		return FALSE;
+	}
+	token = strsep(&o_copy, " ");  /* Version         */
+	if (!o_copy) {
+		ast_log(LOG_WARNING, "SDP syntax error in o= line\n");
+		return FALSE;
+	}
+	if (!sscanf(token, "%30" SCNd64, &rua_version)) {
+		ast_log(LOG_WARNING, "SDP syntax error in o= line version\n");
+		return FALSE;
+	}
+
+	/* we need to check the SDP version number the other end sent us;
+	 * our rules for deciding what to accept are a bit complex.
+	 *
+	 * 1) if 'ignoresdpversion' has been set for this dialog, then
+	 *    we will just accept whatever they sent and assume it is
+	 *    a modification of the session, even if it is not
+	 * 2) otherwise, if this is the first SDP we've seen from them
+	 *    we accept it
+	 * 3) otherwise, if the new SDP version number is higher than the
+	 *    old one, we accept it
+	 * 4) otherwise, if this SDP is in response to us requesting a switch
+	 *    to T.38, we accept the SDP, but also generate a warning message
+	 *    that this peer should have the 'ignoresdpversion' option set,
+	 *    because it is not following the SDP offer/answer RFC; if we did
+	 *    not request a switch to T.38, then we stop parsing the SDP, as it
+	 *    has not changed from the previous version
+	 */
+
+	if (ast_test_flag(&p->flags[1], SIP_PAGE2_IGNORESDPVERSION) ||
+	    (p->sessionversion_remote < 0) ||
+	    (p->sessionversion_remote < rua_version)) {
+		p->sessionversion_remote = rua_version;
+		p->session_modify = TRUE;
+	} else {
+		if (p->t38.state == T38_LOCAL_REINVITE) {
+			p->sessionversion_remote = rua_version;
+			p->session_modify = TRUE;
+			ast_log(LOG_WARNING, "Call %s responded to our T.38 reinvite without changing SDP version; 'ignoresdpversion' should be set for this peer.\n", p->callid);
+		} else {
+			p->session_modify = FALSE;
+			ast_debug(2, "Call %s responded to our reinvite without changing SDP version; ignoring SDP.\n", p->callid);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static int process_sdp_c(const char *c, struct ast_hostent *ast_hp)
+{
+	char host[258];
+	struct hostent *hp;
+
+	/* Check for Media-description-level-address */
+	if (sscanf(c, "IN IP4 %255s", host) != 1) {
+		ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
+		return FALSE;
+	} else {
+		if (!(hp = ast_gethostbyname(host, ast_hp))) {
+			ast_log(LOG_WARNING, "Unable to lookup RTP Audio host in c= line, '%s'\n", c);
+			return FALSE;
+		}
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static int process_sdp_a_sendonly(const char *a, int *sendonly)
+{
+	int found = FALSE;
+
+	if (!strcasecmp(a, "sendonly")) {
+		if (*sendonly == -1)
+			*sendonly = 1;
+		found = TRUE;
+	} else if (!strcasecmp(a, "inactive")) {
+		if (*sendonly == -1)
+			*sendonly = 2;
+		found = TRUE;
+	}  else if (!strcasecmp(a, "sendrecv")) {
+		if (*sendonly == -1)
+			*sendonly = 0;
+		found = TRUE;
+	}
+	return found;
+}
+
+static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newaudiortp, int *last_rtpmap_codec)
+{
+	int found = FALSE;
+	int codec;
+	char mimeSubtype[128];
+	char fmtp_string[64];
+	unsigned int sample_rate;
+	int debug = sip_debug_test_pvt(p);
+
+	if (!strncasecmp(a, "ptime", 5)) {
+		char *tmp = strrchr(a, ':');
+		long int framing = 0;
+		if (tmp) {
+			tmp++;
+			framing = strtol(tmp, NULL, 10);
+			if (framing == LONG_MIN || framing == LONG_MAX) {
+				framing = 0;
+				ast_debug(1, "Can't read framing from SDP: %s\n", a);
+			}
+		}
+		if (framing && p->autoframing) {
+			struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(p->rtp)->pref;
+			int codec_n;
+			for (codec_n = 0; codec_n < AST_RTP_MAX_PT; codec_n++) {
+				struct ast_rtp_payload_type format = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(p->rtp), codec_n);
+				if (!format.asterisk_format || !format.code)	/* non-codec or not found */
+					continue;
+				if (option_debug)
+					ast_log(LOG_DEBUG, "Setting framing for %s to %ld\n", ast_getformatname(format.code), framing);
+				ast_codec_pref_setsize(pref, format.code, framing);
+			}
+			ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, pref);
+		}
+		found = TRUE;
+	} else if (sscanf(a, "rtpmap: %30u %127[^/]/%30u", &codec, mimeSubtype, &sample_rate) == 3) {
+		/* We have a rtpmap to handle */
+		if (*last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
+			if (ast_rtp_codecs_payloads_set_rtpmap_type_rate(newaudiortp, NULL, codec, "audio", mimeSubtype,
+			    ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0, sample_rate) != -1) {
+				if (debug)
+					ast_verbose("Found audio description format %s for ID %d\n", mimeSubtype, codec);
+				//found_rtpmap_codecs[last_rtpmap_codec] = codec;
+				(*last_rtpmap_codec)++;
+				found = TRUE;
+			} else {
+				ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec);
+				if (debug)
+					ast_verbose("Found unknown media description format %s for ID %d\n", mimeSubtype, codec);
+			}
+		} else {
+			if (debug)
+				ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec);
+		}
+	} else if (sscanf(a, "fmtp: %30u %63s", &codec, fmtp_string) == 2) {
+		struct ast_rtp_payload_type payload;
+
+		payload = ast_rtp_codecs_payload_lookup(newaudiortp, codec);
+		if (payload.code && payload.asterisk_format) {
+			unsigned int bit_rate;
+
+			switch (payload.code) {
+			case AST_FORMAT_SIREN7:
+				if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
+					if (bit_rate != 32000) {
+						ast_log(LOG_WARNING, "Got Siren7 offer at %d bps, but only 32000 bps supported; ignoring.\n", bit_rate);
+						ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec);
+					} else {
+						found = TRUE;
+					}
+				}
+				break;
+			case AST_FORMAT_SIREN14:
+				if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
+					if (bit_rate != 48000) {
+						ast_log(LOG_WARNING, "Got Siren14 offer at %d bps, but only 48000 bps supported; ignoring.\n", bit_rate);
+						ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec);
+					} else {
+						found = TRUE;
+					}
+				}
+				break;
+			}
+		}
+	}
+
+	return found;
+}
+
+static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newvideortp, int *last_rtpmap_codec)
+{
+	int found = FALSE;
+	int codec;
+	char mimeSubtype[128];
+	unsigned int sample_rate;
+	int debug = sip_debug_test_pvt(p);
+
+	if (sscanf(a, "rtpmap: %30u %127[^/]/%30u", &codec, mimeSubtype, &sample_rate) == 3) {
+		/* We have a rtpmap to handle */
+		if (*last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
+			/* Note: should really look at the '#chans' params too */
+			if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)) {
+				if (ast_rtp_codecs_payloads_set_rtpmap_type_rate(newvideortp, NULL, codec, "video", mimeSubtype, 0, sample_rate) != -1) {
+					if (debug)
+						ast_verbose("Found video description format %s for ID %d\n", mimeSubtype, codec);
+					//found_rtpmap_codecs[last_rtpmap_codec] = codec;
+					(*last_rtpmap_codec)++;
+					found = TRUE;
+				} else {
+					ast_rtp_codecs_payloads_unset(newvideortp, NULL, codec);
+					if (debug)
+						ast_verbose("Found unknown media description format %s for ID %d\n", mimeSubtype, codec);
+				}
+			}
+		} else {
+			if (debug)
+				ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec);
+		}
+	}
+
+	return found;
+}
+
+static int process_sdp_a_text(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newtextrtp, char *red_fmtp, int *red_num_gen, int *red_data_pt, int *last_rtpmap_codec)
+{
+	int found = FALSE;
+	int codec;
+	char mimeSubtype[128];
+	unsigned int sample_rate;
+	char *red_cp;
+	int debug = sip_debug_test_pvt(p);
+
+	if (sscanf(a, "rtpmap: %30u %127[^/]/%30u", &codec, mimeSubtype, &sample_rate) == 3) {
+		/* We have a rtpmap to handle */
+		if (*last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
+			if (!strncasecmp(mimeSubtype, "T140", 4)) { /* Text */
+				if (p->trtp) {
+					/* ast_verbose("Adding t140 mimeSubtype to textrtp struct\n"); */
+					ast_rtp_codecs_payloads_set_rtpmap_type_rate(newtextrtp, NULL, codec, "text", mimeSubtype, 0, sample_rate);
+					found = TRUE;
+				}
+			} else if (!strncasecmp(mimeSubtype, "RED", 3)) { /* Text with Redudancy */
+				if (p->trtp) {
+					ast_rtp_codecs_payloads_set_rtpmap_type_rate(newtextrtp, NULL, codec, "text", mimeSubtype, 0, sample_rate);
+					sprintf(red_fmtp, "fmtp:%d ", codec);
+					if (debug)
+						ast_verbose("RED submimetype has payload type: %d\n", codec);
+					found = TRUE;
+				}
+			}
+		} else {
+			if (debug)
+				ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec);
+		}
+	} else if (!strncmp(a, red_fmtp, strlen(red_fmtp))) {
+		/* count numbers of generations in fmtp */
+		red_cp = &red_fmtp[strlen(red_fmtp)];
+		strncpy(red_fmtp, a, 100);
+
+		sscanf(red_cp, "%30u", &red_data_pt[*red_num_gen]);
+		red_cp = strtok(red_cp, "/");
+		while (red_cp && (*red_num_gen)++ < AST_RED_MAX_GENERATION) {
+			sscanf(red_cp, "%30u", &red_data_pt[*red_num_gen]);
+			red_cp = strtok(NULL, "/");
+		}
+		red_cp = red_fmtp;
+		found = TRUE;
+	}
+
+	return found;
+}
+
+static int process_sdp_a_image(const char *a, struct sip_pvt *p)
+{
+	int found = FALSE;
+	char s[256];
+	int x;
+
+	if ((sscanf(a, "T38FaxMaxBuffer:%30d", &x) == 1)) {
+		ast_debug(3, "MaxBufferSize:%d\n", x);
+		found = TRUE;
+	} else if ((sscanf(a, "T38MaxBitRate:%30d", &x) == 1) || (sscanf(a, "T38FaxMaxRate:%30d", &x) == 1)) {
+		ast_debug(3, "T38MaxBitRate: %d\n", x);
+		switch (x) {
+		case 14400:
+			p->t38.their_parms.rate = AST_T38_RATE_14400;
+			break;
+		case 12000:
+			p->t38.their_parms.rate = AST_T38_RATE_12000;
+			break;
+		case 9600:
+			p->t38.their_parms.rate = AST_T38_RATE_9600;
+			break;
+		case 7200:
+			p->t38.their_parms.rate = AST_T38_RATE_7200;
+			break;
+		case 4800:
+			p->t38.their_parms.rate = AST_T38_RATE_4800;
+			break;
+		case 2400:
+			p->t38.their_parms.rate = AST_T38_RATE_2400;
+			break;
+		}
+		found = TRUE;
+	} else if ((sscanf(a, "T38FaxVersion:%30d", &x) == 1)) {
+		ast_debug(3, "FaxVersion: %d\n", x);
+		p->t38.their_parms.version = x;
+		found = TRUE;
+	} else if ((sscanf(a, "T38FaxMaxDatagram:%30d", &x) == 1) || (sscanf(a, "T38MaxDatagram:%30d", &x) == 1)) {
+		/* override the supplied value if the configuration requests it */
+		if (p->t38_maxdatagram > x) {
+			ast_debug(1, "Overriding T38FaxMaxDatagram '%d' with '%d'\n", x, p->t38_maxdatagram);
+			x = p->t38_maxdatagram;
+		}
+		ast_debug(3, "FaxMaxDatagram: %d\n", x);
+		ast_udptl_set_far_max_datagram(p->udptl, x);
+		found = TRUE;
+	} else if ((strncmp(a, "T38FaxFillBitRemoval", 20) == 0)) {
+		if (sscanf(a, "T38FaxFillBitRemoval:%30d", &x) == 1) {
+			ast_debug(3, "FillBitRemoval: %d\n", x);
+			if (x == 1) {
+				p->t38.their_parms.fill_bit_removal = TRUE;
+			}
+		} else {
+			ast_debug(3, "FillBitRemoval\n");
+			p->t38.their_parms.fill_bit_removal = TRUE;
+		}
+		found = TRUE;
+	} else if ((strncmp(a, "T38FaxTranscodingMMR", 20) == 0)) {
+		if (sscanf(a, "T38FaxTranscodingMMR:%30d", &x) == 1) {
+			ast_debug(3, "Transcoding MMR: %d\n", x);
+			if (x == 1) {
+				p->t38.their_parms.transcoding_mmr = TRUE;
+			}
+		} else {
+			ast_debug(3, "Transcoding MMR\n");
+			p->t38.their_parms.transcoding_mmr = TRUE;
+		}
+		found = TRUE;
+	} else if ((strncmp(a, "T38FaxTranscodingJBIG", 21) == 0)) {
+		if (sscanf(a, "T38FaxTranscodingJBIG:%30d", &x) == 1) {
+			ast_debug(3, "Transcoding JBIG: %d\n", x);
+			if (x == 1) {
+				p->t38.their_parms.transcoding_jbig = TRUE;
+			}
+		} else {
+			ast_debug(3, "Transcoding JBIG\n");
+			p->t38.their_parms.transcoding_jbig = TRUE;
+		}
+		found = TRUE;
+	} else if ((sscanf(a, "T38FaxRateManagement:%255s", s) == 1)) {
+		ast_debug(3, "RateManagement: %s\n", s);
+		if (!strcasecmp(s, "localTCF"))
+			p->t38.their_parms.rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
+		else if (!strcasecmp(s, "transferredTCF"))
+			p->t38.their_parms.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
+		found = TRUE;
+	} else if ((sscanf(a, "T38FaxUdpEC:%255s", s) == 1)) {
+		ast_debug(3, "UDP EC: %s\n", s);
+		if (!strcasecmp(s, "t38UDPRedundancy")) {
+			ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY);
+		} else if (!strcasecmp(s, "t38UDPFEC")) {
+			ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_FEC);
+		} else {
+			ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE);
+		}
+		found = TRUE;
+	}
+
+	return found;
+}
+
+
 #ifdef LOW_MEMORY
 static void ts_ast_rtp_destroy(void *data)
 {