diff --git a/CHANGES b/CHANGES
index aef532e79384bd7623cf6841993ef70d33f8adc8..da57b1823218d80af71794f40499c824e6ac34d9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -101,3 +101,4 @@ SIP changes
     "sipregs" for registrations. If it's not defined, "sippeers" will be used for
     registration data, as before.
   * The SIPPEER function have new options for port address, call and pickup groups
+  * Added support for T.140 realtime text in SIP/RTP
diff --git a/CREDITS b/CREDITS
index 248a7eaad1cad93917f5f8cfbf5d9a48491337c5..4afa69b1e612cb2353779a3931d84b73dd6207ef 100644
--- a/CREDITS
+++ b/CREDITS
@@ -137,6 +137,7 @@ Philippe Sultan - RADIUS CDR module
 	INRIA, http://www.inria.fr/
 
 John Martin, Aupix - Improved video support in the SIP channel
+	T.140 text support in RTP/SIP
 
 Steve Underwood - Provided T.38 pass through support.
 
diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c
index f84d6d896b2e85a58456aa224e1dff0c7746ee87..23beb00e1a184bf80b292f991baa25ba3d8cc392 100644
--- a/channels/chan_gtalk.c
+++ b/channels/chan_gtalk.c
@@ -188,7 +188,7 @@ static int gtalk_do_reload(int fd, int argc, char **argv);
 static int gtalk_show_channels(int fd, int argc, char **argv);
 /*----- RTP interface functions */
 static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
-							   struct ast_rtp *vrtp, int codecs, int nat_active);
+							   struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active);
 static enum ast_rtp_get_result gtalk_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
 static int gtalk_get_codec(struct ast_channel *chan);
 
@@ -540,7 +540,7 @@ static int gtalk_get_codec(struct ast_channel *chan)
 	return p->peercapability;
 }
 
-static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
+static int gtalk_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
 {
 	struct gtalk_pvt *p;
 
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index 69a0cc03f3f783b27d7a1358f7ef79859036ec51..acabdc7e4ba584a8000262a5ab4b8ac3fbb22e8e 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -3960,7 +3960,7 @@ static enum ast_rtp_get_result mgcp_get_rtp_peer(struct ast_channel *chan, struc
 		return AST_RTP_TRY_PARTIAL;
 }
 
-static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
+static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
 {
 	/* XXX Is there such thing as video support with MGCP? XXX */
 	struct mgcp_subchannel *sub;
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 20a14f0fb0d32a68a1e740f91c20a121d1cc2cb0..f61ea3a4fe1c7a132178041407994181ba4770cf 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -510,6 +510,7 @@ static const struct cfsip_options {
 #define DEFAULT_TOS_SIP         0               /*!< Call signalling packets should be marked as DSCP CS3, but the default is 0 to be compatible with previous versions. */
 #define DEFAULT_TOS_AUDIO       0               /*!< Audio packets should be marked as DSCP EF (Expedited Forwarding), but the default is 0 to be compatible with previous versions. */
 #define DEFAULT_TOS_VIDEO       0               /*!< Video packets should be marked as DSCP AF41, but the default is 0 to be compatible with previous versions. */
+#define DEFAULT_TOS_TEXT        0               /*!< Text packets should be marked as XXXX XXXX, but the default is 0 to be compatible with previous versions. */
 #define DEFAULT_ALLOW_EXT_DOM	TRUE
 #define DEFAULT_REALM		"asterisk"
 #define DEFAULT_NOTIFYRINGING	TRUE
@@ -563,6 +564,7 @@ static int global_mwitime;		/*!< Time between MWI checks for peers */
 static unsigned int global_tos_sip;		/*!< IP type of service for SIP packets */
 static unsigned int global_tos_audio;		/*!< IP type of service for audio RTP packets */
 static unsigned int global_tos_video;		/*!< IP type of service for video RTP packets */
+static unsigned int global_tos_text;		/*!< IP type of service for text RTP packets */
 static int compactheaders;		/*!< send compact sip headers */
 static int recordhistory;		/*!< Record SIP history. Off by default */
 static int dumphistory;			/*!< Dump history to verbose before destroying SIP dialog */
@@ -794,10 +796,14 @@ struct sip_auth {
 #define SIP_PAGE2_CALL_ONHOLD_INACTIVE	(1 << 24)	/*!< 24: Inactive  */
 #define SIP_PAGE2_RFC2833_COMPENSATE    (1 << 25)	/*!< 25: ???? */
 #define SIP_PAGE2_BUGGY_MWI		(1 << 26)	/*!< 26: Buggy CISCO MWI fix */
+#define SIP_PAGE2_NOTEXT		(1 << 27)	/*!< 26: Text not supported  */
+#define SIP_PAGE2_TEXTSUPPORT		(1 << 28)	/*!< 27: Global text enable */
+#define SIP_PAGE2_DEBUG_TEXT		(1 << 29)	/*!< 28: Global text debug */
 
 #define SIP_PAGE2_FLAGS_TO_COPY \
 	(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | \
-	SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | SIP_PAGE2_BUGGY_MWI)
+	SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | SIP_PAGE2_BUGGY_MWI | \
+	SIP_PAGE2_TEXTSUPPORT )
 
 /* SIP packet flags */
 #define SIP_PKT_DEBUG		(1 << 0)	/*!< Debug this packet */
@@ -833,6 +839,7 @@ static int global_t38_capability = T38FAX_VERSION_0 | T38FAX_RATE_2400 | T38FAX_
 #define sipdebug		ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG)
 #define sipdebug_config		ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONFIG)
 #define sipdebug_console	ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE)
+#define sipdebug_text			ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_TEXT)
 
 /*! \brief T38 States for a call */
 enum t38state {
@@ -976,6 +983,7 @@ struct sip_pvt {
 	struct sockaddr_in sa;			/*!< Our peer */
 	struct sockaddr_in redirip;		/*!< Where our RTP should be going if not to us */
 	struct sockaddr_in vredirip;		/*!< Where our Video RTP should be going if not to us */
+	struct sockaddr_in tredirip;		/*!< Where our Text RTP should be going if not to us */
 	time_t lastrtprx;			/*!< Last RTP received */
 	time_t lastrtptx;			/*!< Last RTP sent */
 	int rtptimeout;				/*!< RTP timeout time */
@@ -1010,6 +1018,7 @@ struct sip_pvt {
 	struct sip_registry *registry;		/*!< If this is a REGISTER dialog, to which registry */
 	struct ast_rtp *rtp;			/*!< RTP Session */
 	struct ast_rtp *vrtp;			/*!< Video RTP session */
+	struct ast_rtp *trtp;			/*!< Text RTP session */
 	struct sip_pkt *packets;		/*!< Packets scheduled for re-transmission */
 	struct sip_history_head *history;	/*!< History of this SIP dialog */
 	struct ast_variable *chanvars;		/*!< Channel variables to set for inbound call */
@@ -1545,9 +1554,10 @@ static int handle_response_register(struct sip_pvt *p, int resp, char *rest, str
 static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
 
 /*----- RTP interface functions */
-static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active);
+static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp,  struct ast_rtp *trtp, int codecs, int nat_active);
 static enum ast_rtp_get_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
 static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
+static enum ast_rtp_get_result sip_get_trtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
 static int sip_get_codec(struct ast_channel *chan);
 static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect);
 
@@ -1571,6 +1581,7 @@ static const struct ast_channel_tech sip_tech = {
 	.read = sip_read,
 	.write = sip_write,
 	.write_video = sip_write,
+	.write_text = sip_write,
 	.indicate = sip_indicate,
 	.transfer = sip_transfer,
 	.fixup = sip_fixup,
@@ -1619,6 +1630,7 @@ static struct ast_rtp_protocol sip_rtp = {
 	type: "SIP",
 	get_rtp_info: sip_get_rtp_peer,
 	get_vrtp_info: sip_get_vrtp_peer,
+	get_trtp_info: sip_get_trtp_peer,
 	set_rtp_peer: sip_set_rtp_peer,
 	get_codec: sip_get_codec,
 };
@@ -2839,6 +2851,11 @@ static void do_setnat(struct sip_pvt *p, int natflags)
 			ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %s\n", mode);
 		ast_udptl_setnat(p->udptl, natflags);
 	}
+	if (p->trtp) {
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Setting NAT on TRTP to %s\n", mode);
+		ast_rtp_setnat(p->trtp, natflags);
+	}
 }
 
 /*! \brief Create address structure from peer reference.
@@ -2860,6 +2877,10 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
 		ast_rtp_destroy(dialog->vrtp);
 		dialog->vrtp = NULL;
 	}
+	if (!ast_test_flag(&dialog->flags[1], SIP_PAGE2_TEXTSUPPORT) && dialog->trtp) {
+		ast_rtp_destroy(dialog->trtp);
+		dialog->trtp = NULL;
+	}
 	dialog->prefs = peer->prefs;
 	if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_T38SUPPORT)) {
 		dialog->t38.capability = global_t38_capability;
@@ -2898,6 +2919,13 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
 		ast_rtp_set_rtpholdtimeout(dialog->vrtp, peer->rtpholdtimeout);
 		ast_rtp_set_rtpkeepalive(dialog->vrtp, peer->rtpkeepalive);
 	}
+	if (dialog->trtp) {
+		ast_rtp_setdtmf(dialog->trtp, 0);
+		ast_rtp_setdtmfcompensate(dialog->trtp, 0);
+		ast_rtp_set_rtptimeout(dialog->trtp, peer->rtptimeout);
+		ast_rtp_set_rtpholdtimeout(dialog->trtp, peer->rtpholdtimeout);
+		ast_rtp_set_rtpkeepalive(dialog->trtp, peer->rtpkeepalive);
+	}
 
 	ast_string_field_set(dialog, peername, peer->username);
 	ast_string_field_set(dialog, authname, peer->username);
@@ -3181,6 +3209,8 @@ static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
 		ast_rtp_destroy(p->rtp);
 	if (p->vrtp)
 		ast_rtp_destroy(p->vrtp);
+	if (p->trtp)
+		ast_rtp_destroy(p->trtp);
 	if (p->udptl)
 		ast_udptl_destroy(p->udptl);
 	if (p->refer)
@@ -3644,10 +3674,13 @@ static int sip_hangup(struct ast_channel *ast)
 			if (!p->pendinginvite) {
 				char *audioqos = "";
 				char *videoqos = "";
+				char *textqos = "";
 				if (p->rtp)
 					audioqos = ast_rtp_get_quality(p->rtp);
 				if (p->vrtp)
 					videoqos = ast_rtp_get_quality(p->vrtp);
+				if (p->trtp)
+					textqos = ast_rtp_get_quality(p->trtp);
 				/* Send a hangup */
 				transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
 
@@ -3657,11 +3690,15 @@ static int sip_hangup(struct ast_channel *ast)
 						append_history(p, "RTCPaudio", "Quality:%s", audioqos);
 					if (p->vrtp)
 						append_history(p, "RTCPvideo", "Quality:%s", videoqos);
+					if (p->trtp)
+						append_history(p, "RTCPtext", "Quality:%s", textqos);
 				}
 				if (p->rtp && oldowner)
 					pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOS", audioqos);
 				if (p->vrtp && oldowner)
 					pbx_builtin_setvar_helper(oldowner, "RTPVIDEOQOS", videoqos);
+				if (p->trtp && oldowner)
+					pbx_builtin_setvar_helper(oldowner, "RTPTEXTQOS", textqos);
 			} else {
 				/* Note we will need a BYE when this all settles out
 				   but we can't send one while we have "INVITE" outstanding. */
@@ -3779,6 +3816,23 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
 			sip_pvt_unlock(p);
 		}
 		break;
+	case AST_FRAME_TEXT:
+		if (p) {
+			sip_pvt_lock(p);
+			if (p->trtp) {
+				/* Activate text early media */
+				if ((ast->_state != AST_STATE_UP) &&
+				    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
+				    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+					transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
+					ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);	
+				}
+				p->lastrtptx = time(NULL);
+				res = ast_rtp_write(p->trtp, frame);
+			}
+			sip_pvt_unlock(p);
+		}
+		break;
 	case AST_FRAME_IMAGE:
 		return 0;
 		break;
@@ -4010,7 +4064,10 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 	struct ast_variable *v = NULL;
 	int fmt;
 	int what;
+	int video;
+	int text;
 	int needvideo = 0;
+	int needtext = 0;
 	{
 		const char *my_name;	/* pick a good name */
 	
@@ -4040,15 +4097,22 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 
 	/* Select our native format based on codec preference until we receive
 	   something from another device to the contrary. */
-	if (i->jointcapability)	 	/* The joint capabilities of us and peer */
+	if (i->jointcapability) { 	/* The joint capabilities of us and peer */
 		what = i->jointcapability;
-	else if (i->capability)		/* Our configured capability for this peer */
+		video = i->jointcapability & AST_FORMAT_VIDEO_MASK;
+		text = i->jointcapability & AST_FORMAT_TEXT_MASK;
+	} else if (i->capability) {		/* Our configured capability for this peer */
 		what = i->capability;
-	else
+		video = i->capability & AST_FORMAT_VIDEO_MASK;
+		text = i->capability & AST_FORMAT_TEXT_MASK;
+	} else {
 		what = global_capability;	/* Global codec support */
+		video = global_capability & AST_FORMAT_VIDEO_MASK;
+		text = global_capability & AST_FORMAT_TEXT_MASK;
+	}
 
 	/* 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);
+	tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | video | text;
 	if (option_debug > 2) {
 		char buf[BUFSIZ];
 		ast_log(LOG_DEBUG, "*** Our native formats are %s \n", ast_getformatname_multiple(buf, BUFSIZ, tmp->nativeformats));
@@ -4073,6 +4137,13 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 			needvideo = i->jointcapability & AST_FORMAT_VIDEO_MASK;	/* Inbound call */
 	}
 
+	if (i->trtp) {
+		if (i->prefcodec)
+			needtext = i->prefcodec & AST_FORMAT_TEXT_MASK;	/* Outbound call */
+ 		else
+			needtext = i->jointcapability & AST_FORMAT_TEXT_MASK;	/* Inbound call */
+	}
+
 	if (option_debug > 2) {
 		if (needvideo) 
 			ast_log(LOG_DEBUG, "This channel can handle video! HOLLYWOOD next!\n");
@@ -4096,6 +4167,9 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 		tmp->fds[2] = ast_rtp_fd(i->vrtp);
 		tmp->fds[3] = ast_rtcp_fd(i->vrtp);
 	}
+	if (needtext && i->trtp) {
+		tmp->fds[4] = ast_rtp_fd(i->trtp);
+	}
 	if (i->udptl) {
 		tmp->fds[5] = ast_udptl_fd(i->udptl);
 	}
@@ -4314,6 +4388,19 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
 	case 3:
 		f = ast_rtcp_read(p->vrtp);	/* RTCP Control Channel for video */
 		break;
+	case 4:
+		f = ast_rtp_read(p->trtp);	/* RTP Text */
+		if (sipdebug_text) {
+			int i;
+			unsigned char* arr = f->data;
+			for (i=0; i < f->datalen; i++)
+				ast_verbose("%c", (arr[i] > ' ' && arr[i] < '}') ? arr[i] : '.');
+			ast_verbose(" -> ");
+			for (i=0; i < f->datalen; i++)
+				ast_verbose("%02X ", arr[i]);
+			ast_verbose("\n");
+		}
+		break;
 	case 5:
 		f = ast_udptl_read(p->udptl);	/* UDPTL for T.38 */
 		break;
@@ -4331,7 +4418,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
 			if (f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
 				if (option_debug)
 					ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
-				p->owner->nativeformats = (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass;
+				p->owner->nativeformats = (p->owner->nativeformats & (AST_FORMAT_VIDEO_MASK | AST_FORMAT_TEXT_MASK)) | f->subclass;
 				ast_set_read_format(p->owner, p->owner->readformat);
 				ast_set_write_format(p->owner, p->owner->writeformat);
 			}
@@ -4475,11 +4562,15 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
 		/* If the global videosupport flag is on, we always create a RTP interface for video */
 		if (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT))
 			p->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
+ 		if (ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT))
+ 			p->trtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
 		if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT))
 			p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr);
-		if (!p->rtp || (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && !p->vrtp)) {
-			ast_log(LOG_WARNING, "Unable to create RTP audio %s session: %s\n",
-				ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "and video" : "", strerror(errno));
+ 		if (!p->rtp|| (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && !p->vrtp) 
+				|| (ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT) && !p->trtp)) {
+ 			ast_log(LOG_WARNING, "Unable to create RTP audio %s%ssession: %s\n",
+ 				ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "and video " : "",
+ 				ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT) ? "and text " : "", strerror(errno));
 			ast_mutex_destroy(&p->pvt_lock);
 			if (p->chanvars) {
 				ast_variables_destroy(p->chanvars);
@@ -4502,6 +4593,11 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
 			ast_rtp_set_rtpholdtimeout(p->vrtp, global_rtpholdtimeout);
 			ast_rtp_set_rtpkeepalive(p->vrtp, global_rtpkeepalive);
 		}
+		if (p->trtp) {
+			ast_rtp_settos(p->trtp, global_tos_text);
+			ast_rtp_setdtmf(p->trtp, 0);
+			ast_rtp_setdtmfcompensate(p->trtp, 0);
+		}
 		if (p->udptl)
 			ast_udptl_settos(p->udptl, global_tos_audio);
 		p->maxcallbitrate = default_maxcallbitrate;
@@ -4944,6 +5040,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 	int len = -1;
 	int portno = -1;		/*!< RTP Audio port number */
 	int vportno = -1;		/*!< RTP Video port number */
+	int tportno = -1;		/*!< RTP Text port number */
 	int udptlportno = -1;
 	int peert38capability = 0;
 	char s[256];
@@ -4952,20 +5049,24 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 	/* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */	
 	int peercapability = 0, peernoncodeccapability = 0;
 	int vpeercapability = 0, vpeernoncodeccapability = 0;
+	int tpeercapability = 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 = 0;
 	int numberofports;
-	struct ast_rtp *newaudiortp, *newvideortp;	/* Buffers for codec handling */
+	struct ast_rtp *newaudiortp, *newvideortp, *newtextrtp;	/* Buffers for codec handling */
 	int newjointcapability;				/* Negotiated capability */
 	int newpeercapability;
 	int newnoncodeccapability;
@@ -4991,6 +5092,11 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 	ast_rtp_new_init(newvideortp);
 	ast_rtp_pt_clear(newvideortp);
 
+	newtextrtp = alloca(ast_rtp_alloc_size());
+	memset(newtextrtp, 0, ast_rtp_alloc_size());
+	ast_rtp_new_init(newtextrtp);
+	ast_rtp_pt_clear(newtextrtp);
+
 	/* Update our last rtprx when we receive an SDP, too */
 	p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
 
@@ -5017,15 +5123,24 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 		return -1;
 	}
 	vhp = hp;	/* Copy to video address as default too */
+	thp = hp;	/* Copy to video address as default too */
 	
 	iterator = req->sdp_start;
 	ast_set_flag(&p->flags[0], SIP_NOVIDEO);	
+	ast_set_flag(&p->flags[1], SIP_PAGE2_NOTEXT);	
 
+	if (p->vrtp)
+		ast_rtp_pt_clear(newvideortp);  /* Must be cleared in case no m=video line exists */
+ 
+	if (p->trtp)
+		ast_rtp_pt_clear(newtextrtp);  /* Must be cleared in case no m=text line exists */
 
 	/* Find media streams in this SDP offer */
 	while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
 		int x;
 		int audio = FALSE;
+		int video = FALSE;
+		int text = FALSE;
 
 		numberofports = 1;
 		if ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2) ||
@@ -5046,7 +5161,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 			}
 		} 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 ? */
+			video = TRUE;
 			ast_clear_flag(&p->flags[0], SIP_NOVIDEO);	
 			numberofmediastreams++;
 			vportno = x;
@@ -5060,6 +5175,22 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 					ast_verbose("Found RTP video format %d\n", codec);
 				ast_rtp_set_m_type(newvideortp, codec);
 			}
+		} else if ((sscanf(m, "text %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2) ||
+		    (sscanf(m, "text %d RTP/AVP %n", &x, &len) == 1)) {
+			text = TRUE;
+			ast_clear_flag(&p->flags[1], SIP_PAGE2_NOTEXT);	
+			numberofmediastreams++;
+			tportno = x;
+			/* Scan through the RTP payload types specified in a "m=" line: */
+			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);
+					return -1;
+				}
+				if (debug)
+					ast_verbose("Found RTP text format %d\n", codec);
+				ast_rtp_set_m_type(newtextrtp, codec);
+			}
 		} else if (p->udptl && ( (sscanf(m, "image %d udptl t38%n", &x, &len) == 1) || 
 		 (sscanf(m, "image %d UDPTL t38%n", &x, &len) == 1) )) {
 			if (debug)
@@ -5092,27 +5223,35 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 				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);
+				} 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);
+				} 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);
+				}
 			}
 
 		}
 	}
-	if (portno == -1 && vportno == -1 && udptlportno == -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 */
 		return -2;
 
-	if (numberofmediastreams > 2)
-		/* We have too many fax, audio and/or video media streams, fail this offer */
+	if (numberofmediastreams > 3)
+		/* 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) {
@@ -5146,11 +5285,15 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 			}
 		}
 	}
-	/* Setup video port number */
+	/* Setup video port number, assumes we have audio */
 	if (vportno != -1)
 		vsin.sin_port = htons(vportno);
 
-	/* Next, scan through each "a=rtpmap:" line, noting each
+	/* 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 */
@@ -5240,10 +5383,18 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 			last_rtpmap_codec++;
 
 			/* Note: should really look at the 'freq' and '#chans' params too */
-			ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype,
-					ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0);
-			if (p->vrtp)
-				ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0);
+			/* Note: This should all be done in the context of the m= above */
+			if (!strncasecmp(mimeSubtype, "H26",3)) {         /* Video */
+				/* Not going to do anything here for the moment, but we will soon */
+			} else if (!strncasecmp(mimeSubtype, "T140",4)) { /* Text */
+				if (p->trtp) {
+					/* ast_verbose("Adding t140 mimeSubtype to textrtp struct\n"); */
+					ast_rtp_set_rtpmap_type(newtextrtp, codec, "text", mimeSubtype, 0);
+				}
+			} else {                                          /* Must be audio?? */
+				ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype,
+						ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0);
+			}
 		}
 	}
 	
@@ -5360,21 +5511,23 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 	/* 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);
+	ast_rtp_get_current_formats(newtextrtp, &tpeercapability, &tpeernoncodeccapability);
+ 
+	newjointcapability = p->capability & (peercapability | vpeercapability | tpeercapability);
+	newpeercapability = (peercapability | vpeercapability | tpeercapability);
 	newnoncodeccapability = p->noncodeccapability & peernoncodeccapability;
 		
 		
 	if (debug) {
 		/* shame on whoever coded this.... */
-		char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ], s4[BUFSIZ];
+		char s1[BUFSIZ], s2[BUFSIZ], s3[BUFSIZ], s4[BUFSIZ], s5[BUFSIZ];
 
-		ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s, combined - %s\n",
+		ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s/text=%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_getformatname_multiple(s4, BUFSIZ, tpeercapability),
+			    ast_getformatname_multiple(s5, BUFSIZ, newjointcapability));
 
 		ast_verbose("Non-codec capabilities (dtmf): us - %s, peer - %s, combined - %s\n",
 			    ast_rtp_lookup_mime_multiple(s1, BUFSIZ, p->noncodeccapability, 0, 0),
@@ -5403,6 +5556,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 	ast_rtp_pt_copy(p->rtp, newaudiortp);
 	if (p->vrtp)
 		ast_rtp_pt_copy(p->vrtp, newvideortp);
+	if (p->trtp)
+		ast_rtp_pt_copy(p->trtp, newtextrtp);
 
 	if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO) {
 		ast_clear_flag(&p->flags[0], SIP_DTMF);
@@ -5431,6 +5586,13 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 			ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(vsin.sin_addr), ntohs(vsin.sin_port));
 	}
 
+	/* Setup text port number */
+	if (p->trtp && tsin.sin_port) {
+		ast_rtp_set_peer(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));
+	}
+
 	/* Ok, we're going with this offer */
 	if (option_debug > 1) {
 		char buf[BUFSIZ];
@@ -5450,7 +5612,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 				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);
+		p->owner->nativeformats = ast_codec_choose(&p->prefs, p->jointcapability, 1) | (p->capability & vpeercapability) | (p->capability & tpeercapability);
 		ast_set_read_format(p->owner, p->owner->readformat);
 		ast_set_write_format(p->owner, p->owner->writeformat);
 	}
@@ -6187,6 +6349,52 @@ static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate
 		*min_packet_size = fmt.cur_ms;
 }
 
+/*! \brief Add video codec offer to SDP offer/answer body in INVITE or 200 OK */
+/* This is different to the audio one now so we can add more caps later */
+static void add_vcodec_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, int *min_packet_size)
+{
+	int rtp_code;
+
+	if (!p->vrtp)
+		return;
+
+	if (debug)
+		ast_verbose("Adding video codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
+
+	if ((rtp_code = ast_rtp_lookup_code(p->vrtp, 1, codec)) == -1)
+		return;
+
+	ast_build_string(m_buf, m_size, " %d", rtp_code);
+	ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", rtp_code,
+			 ast_rtp_lookup_mime_subtype(1, codec, 0), sample_rate);
+	/* Add fmtp code here */
+}
+
+/*! \brief Add text codec offer to SDP offer/answer body in INVITE or 200 OK */
+static void add_tcodec_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, int *min_packet_size)
+{
+	int rtp_code;
+
+	if (!p->trtp)
+		return;
+
+	if (debug)
+		ast_verbose("Adding text codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
+
+	if ((rtp_code = ast_rtp_lookup_code(p->trtp, 1, codec)) == -1)
+		return;
+
+	ast_build_string(m_buf, m_size, " %d", rtp_code);
+	ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", rtp_code,
+			 ast_rtp_lookup_mime_subtype(1, codec, 0), sample_rate);
+	/* Add fmtp code here */
+}
+
+
 /*! \brief Get Max T.38 Transmission rate from T38 capabilities */
 static int t38_get_rate(int t38cap)
 {
@@ -6344,12 +6552,14 @@ static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_
 /*! \brief Set all IP media addresses for this call 
 	\note called from add_sdp()
 */
-static void get_our_media_address(struct sip_pvt *p, int needvideo, struct sockaddr_in *sin, struct sockaddr_in *vsin, struct sockaddr_in *dest, struct sockaddr_in *vdest)
+static void get_our_media_address(struct sip_pvt *p, int needvideo, struct sockaddr_in *sin, struct sockaddr_in *vsin, struct sockaddr_in *tsin, struct sockaddr_in *dest, struct sockaddr_in *vdest)
 {
 	/* First, get our address */
 	ast_rtp_get_us(p->rtp, sin);
 	if (p->vrtp)
 		ast_rtp_get_us(p->vrtp, vsin);
+	if (p->trtp)
+		ast_rtp_get_us(p->trtp, tsin);
 
 	/* Now, try to figure out where we want them to send data */
 	/* Is this a re-invite to move the media out, then use the original offer from caller  */
@@ -6383,8 +6593,10 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
 
 	struct sockaddr_in sin;
 	struct sockaddr_in vsin;
+	struct sockaddr_in tsin;
 	struct sockaddr_in dest;
 	struct sockaddr_in vdest = { 0, };
+	struct sockaddr_in tdest = { 0, };
 
 	/* SDP fields */
 	char *version = 	"v=0\r\n";		/* Protocol version */
@@ -6396,25 +6608,34 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
 	char *hold;
 	char m_audio[256];				/* Media declaration line for audio */
 	char m_video[256];				/* Media declaration line for video */
+	char m_text[256];				  /* Media declaration line for text */
 	char a_audio[1024];				/* Attributes for audio */
 	char a_video[1024];				/* Attributes for video */
+	char a_text[1024];				/* Attributes for text */
 	char *m_audio_next = m_audio;
 	char *m_video_next = m_video;
+	char *m_text_next = m_text;
 	size_t m_audio_left = sizeof(m_audio);
 	size_t m_video_left = sizeof(m_video);
+	size_t m_text_left = sizeof(m_text);
 	char *a_audio_next = a_audio;
 	char *a_video_next = a_video;
+	char *a_text_next = a_text;
 	size_t a_audio_left = sizeof(a_audio);
 	size_t a_video_left = sizeof(a_video);
+	size_t a_text_left = sizeof(a_text);
 
 	int x;
 	int capability;
 	int needvideo = FALSE;
+	int needtext = FALSE;
 	int debug = sip_debug_test_pvt(p);
 	int min_audio_packet_size = 0;
 	int min_video_packet_size = 0;
+	int min_text_packet_size = 0;
 
 	m_video[0] = '\0';	/* Reset the video media string if it's not needed */
+	m_text[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");
@@ -6434,7 +6655,8 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
 
 	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 capability: %s Video flag: %s Text flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability), 
+ 			ast_test_flag(&p->flags[0], SIP_NOVIDEO) ? "True" : "False", ast_test_flag(&p->flags[1], SIP_PAGE2_NOTEXT) ? "True" : "False");
 		ast_log(LOG_DEBUG, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec));
 	}
 	
@@ -6456,8 +6678,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
 	}
 
 	/* Get our media addresses */
-	get_our_media_address(p, needvideo, &sin, &vsin, &dest, &vdest);
+	get_our_media_address(p, needvideo, &sin, &vsin, &tsin, &dest, &vdest);
 		
+	if (debug) 
+		ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(p->ourip), ntohs(sin.sin_port));	
+
 	/* 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) {
@@ -6470,8 +6695,36 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
 			ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(p->ourip), ntohs(vsin.sin_port));	
 	}
 
-	if (debug) 
-		ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(p->ourip), ntohs(sin.sin_port));	
+	/* Check if we need text in this call */
+	if((capability & AST_FORMAT_TEXT_MASK) && !ast_test_flag(&p->flags[1], SIP_PAGE2_NOTEXT)) {
+		if (sipdebug_text) ast_verbose("We think we can do text\n");
+		if (p->trtp) {
+			if (sipdebug_text) ast_verbose("And we have a text rtp object\n");
+			needtext = TRUE;
+			if (option_debug > 1)
+				ast_log(LOG_DEBUG, "This call needs text offers! \n");
+		} else if (option_debug > 1)
+			ast_log(LOG_DEBUG, "This call needs text offers, but there's no text support enabled ! \n");
+	}
+		
+	/* Ok, we need text. Let's add what we need for text and set codecs.
+	   Text is handled differently than audio since we can not transcode. */
+	if (needtext) {
+		if (sipdebug_text) ast_verbose("Lets set up the text sdp\n");
+		/* Determine text destination */
+		if (p->tredirip.sin_addr.s_addr) {
+			tdest.sin_addr = p->tredirip.sin_addr;
+			tdest.sin_port = p->tredirip.sin_port;
+		} else {
+			tdest.sin_addr = p->ourip;
+			tdest.sin_port = tsin.sin_port;
+		}
+		ast_build_string(&m_text_next, &m_text_left, "m=text %d RTP/AVP", ntohs(tdest.sin_port));
+
+		if (debug) 
+			ast_verbose("Text is at %s port %d\n", ast_inet_ntoa(p->ourip), ntohs(tsin.sin_port));	
+
+	}
 
 	/* Start building generic SDP headers */
 
@@ -6529,7 +6782,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
 	}
 
 	/* 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) {
+	for (x = 1; x <= (needtext ? AST_FORMAT_MAX_TEXT : (needvideo ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO)); x <<= 1) {
 		if (!(capability & x))	/* Codec not requested */
 			continue;
 
@@ -6541,11 +6794,16 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
 					 &m_audio_next, &m_audio_left,
 					 &a_audio_next, &a_audio_left,
 					 debug, &min_audio_packet_size);
-		else 
-			add_codec_to_sdp(p, x, 90000,
+		else if (x <= AST_FORMAT_MAX_VIDEO) 
+			add_vcodec_to_sdp(p, x, 90000,
 					 &m_video_next, &m_video_left,
 					 &a_video_next, &a_video_left,
 					 debug, &min_video_packet_size);
+		else if (x <= AST_FORMAT_MAX_TEXT)
+			add_tcodec_to_sdp(p, x, 1000,
+					 &m_text_next, &m_text_left,
+					 &a_text_next, &a_text_left,
+					 debug, &min_text_packet_size);
 	}
 
 	/* Now add DTMF RFC2833 telephony-event as a codec */
@@ -6565,21 +6823,32 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
 	if (!p->owner || !ast_internal_timing_enabled(p->owner))
 		ast_build_string(&a_audio_next, &a_audio_left, "a=silenceSupp:off - - - -\r\n");
 
-	if (min_audio_packet_size)
-		ast_build_string(&a_audio_next, &a_audio_left, "a=ptime:%d\r\n", min_audio_packet_size);
-	if (min_video_packet_size)
-		ast_build_string(&a_video_next, &a_video_left, "a=ptime:%d\r\n", min_video_packet_size);
-
-	if ((m_audio_left < 2) || (m_video_left < 2) || (a_audio_left == 0) || (a_video_left == 0))
-		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");
-	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);
+  if (min_audio_packet_size)
+  	ast_build_string(&a_audio_next, &a_audio_left, "a=ptime:%d\r\n", min_audio_packet_size);
+  
+ 	/* XXX don't think you can have ptime for video */
+  if (min_video_packet_size)
+  	ast_build_string(&a_video_next, &a_video_left, "a=ptime:%d\r\n", min_video_packet_size);
+  
+ 	/* XXX don't think you can have ptime for text */
+ 	if (min_text_packet_size)
+ 		ast_build_string(&a_text_next, &a_text_left, "a=ptime:%d\r\n", min_text_packet_size);
+ 
+ 	if ((m_audio_left < 2) || (m_video_left < 2) || (m_text_left < 2) || 
+ 		  (a_audio_left == 0) || (a_video_left == 0) || (a_text_left == 0))
+  		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");
+ 	if (needvideo)
+ 		ast_build_string(&m_video_next, &m_video_left, "\r\n");
+ 	if (needtext)
+ 		ast_build_string(&m_text_next, &m_text_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);
+ 	if (needtext) /* only if text response is appropriate */
+ 		len += strlen(m_text) + strlen(a_text) + strlen(hold);
 
 	add_header(resp, "Content-Type", "application/sdp");
 	add_header_contentLength(resp, len);
@@ -6598,6 +6867,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
 		add_line(resp, a_video);
 		add_line(resp, hold);	/* Repeat hold for the video stream */
 	}
+	if (needtext) { /* only if text response is appropriate */
+		add_line(resp, m_text);
+		add_line(resp, a_text);
+		add_line(resp, hold);	/* Repeat hold for the text stream */
+	}
 
 	/* Update lastrtprx when we send our SDP */
 	p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
@@ -9359,6 +9633,11 @@ static enum check_auth_result check_user_ok(struct sip_pvt *p, char *of,
 			ast_rtp_destroy(p->vrtp);
 			p->vrtp = NULL;
 		}
+		/* If we do not support text, remove text from call structure */
+ 		if (!ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT) && p->trtp) {
+ 			ast_rtp_destroy(p->trtp);
+ 			p->trtp = NULL;
+ 		}
 	}
 	unref_user(user);
 	return res;
@@ -9473,6 +9752,10 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
 			ast_rtp_destroy(p->vrtp);
 			p->vrtp = NULL;
 		}
+		if ((!ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT) || !(p->capability & AST_FORMAT_TEXT_MASK)) && p->trtp) {
+			ast_rtp_destroy(p->trtp);
+			p->trtp = NULL;
+ 		}
 		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;
@@ -9962,6 +10245,7 @@ static int _sip_show_peers(int fd, int *total, struct mansession *s, const struc
 			"Dynamic: %s\r\n"
 			"Natsupport: %s\r\n"
 			"VideoSupport: %s\r\n"
+			"TextSupport: %s\r\n"
 			"ACL: %s\r\n"
 			"Status: %s\r\n"
 			"RealtimeDevice: %s\r\n\r\n", 
@@ -9972,6 +10256,7 @@ static int _sip_show_peers(int fd, int *total, struct mansession *s, const struc
 			ast_test_flag(&iterator->flags[1], SIP_PAGE2_DYNAMIC) ? "yes" : "no", 	/* Dynamic or not? */
 			ast_test_flag(&iterator->flags[0], SIP_NAT_ROUTE) ? "yes" : "no",	/* NAT=yes? */
 			ast_test_flag(&iterator->flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "yes" : "no",	/* VIDEOSUPPORT=yes? */
+			ast_test_flag(&iterator->flags[1], SIP_PAGE2_TEXTSUPPORT) ? "yes" : "no",	/* TEXTSUPPORT=yes? */
 			iterator->ha ? "yes" : "no",       /* permit/deny */
 			status,
 			realtimepeers ? (ast_test_flag(&iterator->flags[0], SIP_REALTIME) ? "yes":"no") : "no");
@@ -10392,6 +10677,7 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, const struct m
 		ast_cli(fd, "  PromiscRedir : %s\n", ast_test_flag(&peer->flags[0], SIP_PROMISCREDIR)?"Yes":"No");
 		ast_cli(fd, "  User=Phone   : %s\n", ast_test_flag(&peer->flags[0], SIP_USEREQPHONE)?"Yes":"No");
 		ast_cli(fd, "  Video Support: %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT)?"Yes":"No");
+		ast_cli(fd, "  Text Support : %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_TEXTSUPPORT)?"Yes":"No");
 		ast_cli(fd, "  Trust RPID   : %s\n", ast_test_flag(&peer->flags[0], SIP_TRUSTRPID) ? "Yes" : "No");
 		ast_cli(fd, "  Send RPID    : %s\n", ast_test_flag(&peer->flags[0], SIP_SENDRPID) ? "Yes" : "No");
 		ast_cli(fd, "  Subscriptions: %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE) ? "Yes" : "No");
@@ -10479,6 +10765,7 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, const struct m
 		astman_append(s, "SIP-PromiscRedir: %s\r\n", (ast_test_flag(&peer->flags[0], SIP_PROMISCREDIR)?"Y":"N"));
 		astman_append(s, "SIP-UserPhone: %s\r\n", (ast_test_flag(&peer->flags[0], SIP_USEREQPHONE)?"Y":"N"));
 		astman_append(s, "SIP-VideoSupport: %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT)?"Y":"N"));
+		astman_append(s, "SIP-TextSupport: %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_TEXTSUPPORT)?"Y":"N"));
 
 		/* - is enumerated */
 		astman_append(s, "SIP-DTMFmode: %s\r\n", dtmfmode2str(ast_test_flag(&peer->flags[0], SIP_DTMF)));
@@ -10628,6 +10915,7 @@ static int sip_show_settings(int fd, int argc, char *argv[])
 	ast_cli(fd, "  SIP Port:               %d\n", ntohs(bindaddr.sin_port));
 	ast_cli(fd, "  Bindaddress:            %s\n", ast_inet_ntoa(bindaddr.sin_addr));
 	ast_cli(fd, "  Videosupport:           %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "Yes" : "No");
+	ast_cli(fd, "  Textsupport:            %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_TEXTSUPPORT) ? "Yes" : "No");
 	ast_cli(fd, "  AutoCreatePeer:         %s\n", autocreatepeer ? "Yes" : "No");
 	ast_cli(fd, "  MatchAuthUsername:      %s\n", global_match_auth_username ? "Yes" : "No");
 	ast_cli(fd, "  Allow unknown access:   %s\n", global_allowguest ? "Yes" : "No");
@@ -10652,6 +10940,7 @@ static int sip_show_settings(int fd, int argc, char *argv[])
 	ast_cli(fd, "  IP ToS SIP:             %s\n", ast_tos2str(global_tos_sip));
 	ast_cli(fd, "  IP ToS RTP audio:       %s\n", ast_tos2str(global_tos_audio));
 	ast_cli(fd, "  IP ToS RTP video:       %s\n", ast_tos2str(global_tos_video));
+	ast_cli(fd, "  IP ToS RTP text:        %s\n", ast_tos2str(global_tos_text));
 	ast_cli(fd, "  T38 fax pt UDPTL:       %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_UDPTL) ? "Yes" : "No");
 #ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
 	ast_cli(fd, "  T38 fax pt RTP:         %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_RTP) ? "Yes" : "No");
@@ -11262,6 +11551,7 @@ static int sip_do_debug(int fd, int argc, char *argv[])
 			return RESULT_SHOWUSAGE;
 	}
 	ast_set_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE);
+	ast_set_flag(&global_flags[1], SIP_PAGE2_DEBUG_TEXT);	/*! \note this can be a special debug command - "sip debug text" or something */
 	memset(&debugaddr, 0, sizeof(debugaddr));
 	ast_cli(fd, "SIP Debugging %senabled\n", oldsipdebug ? "re-" : "");
 	return RESULT_SUCCESS;
@@ -11329,6 +11619,7 @@ static int sip_no_debug(int fd, int argc, char *argv[])
 	if (argc != 4)
 		return RESULT_SHOWUSAGE;
 	ast_clear_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE);
+	ast_clear_flag(&global_flags[1], SIP_PAGE2_DEBUG_TEXT);
 	ast_cli(fd, "SIP Debugging Disabled\n");
 	return RESULT_SUCCESS;
 }
@@ -12510,6 +12801,8 @@ static void stop_media_flows(struct sip_pvt *p)
 		ast_rtp_stop(p->rtp);
 	if (p->vrtp)
 		ast_rtp_stop(p->vrtp);
+	if (p->trtp)
+		ast_rtp_stop(p->trtp);
 	if (p->udptl)
 		ast_udptl_stop(p->udptl);
 }
@@ -14487,7 +14780,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
 
 	/* Get RTCP quality before end of call */
 	if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY) || p->owner) {
-		char *audioqos, *videoqos;
+		char *audioqos, *videoqos, *textqos;
 		if (p->rtp) {
 			audioqos = ast_rtp_get_quality(p->rtp);
 			if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
@@ -14502,6 +14795,13 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
 			if (p->owner)
 				pbx_builtin_setvar_helper(p->owner, "RTPVIDEOQOS", videoqos);
 		}
+		if (p->trtp) {
+			textqos = ast_rtp_get_quality(p->trtp);
+			if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
+				append_history(p, "RTCPtext", "Quality:%s", textqos);
+			if (p->owner)
+				pbx_builtin_setvar_helper(p->owner, "RTPTEXTQOS", textqos);
+		}
 	}
 
 	stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
@@ -15697,6 +15997,7 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
 	printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "<none>", host);
 #endif
 	p->prefcodec = oldformat;				/* Format for this call */
+	p->jointcapability = oldformat;
 	sip_pvt_lock(p);
 	tmpc = sip_new(p, AST_STATE_DOWN, host);	/* Place the call */
 	sip_pvt_unlock(p);
@@ -15819,6 +16120,10 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
 		ast_set_flag(&mask[1], SIP_PAGE2_VIDEOSUPPORT);
 		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_VIDEOSUPPORT);
 		res = 1;
+	} else if (!strcasecmp(v->name, "textsupport")) {
+		ast_set_flag(&mask[1], SIP_PAGE2_TEXTSUPPORT);
+		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_TEXTSUPPORT);
+		res = 1;
 	} else if (!strcasecmp(v->name, "allowoverlap")) {
 		ast_set_flag(&mask[1], SIP_PAGE2_ALLOWOVERLAP);
 		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_ALLOWOVERLAP);
@@ -16517,6 +16822,7 @@ static int reload_config(enum channelreloadreason reason)
 	global_tos_sip = DEFAULT_TOS_SIP;
 	global_tos_audio = DEFAULT_TOS_AUDIO;
 	global_tos_video = DEFAULT_TOS_VIDEO;
+	global_tos_text = DEFAULT_TOS_TEXT;
 	externhost[0] = '\0';			/* External host name (for behind NAT DynDNS support) */
 	externexpire = 0;			/* Expiration for DNS re-issuing */
 	externrefresh = 10;
@@ -16584,6 +16890,7 @@ static int reload_config(enum channelreloadreason reason)
 	memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
 
 	ast_clear_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT);
+	ast_clear_flag(&global_flags[1], SIP_PAGE2_TEXTSUPPORT);
 
 	/* Read the [general] config section of sip.conf (or from realtime config) */
 	for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
@@ -16806,6 +17113,9 @@ static int reload_config(enum channelreloadreason reason)
 		} else if (!strcasecmp(v->name, "tos_video")) {
 			if (ast_str2tos(v->value, &global_tos_video))
 				ast_log(LOG_WARNING, "Invalid tos_video value at line %d, recommended value is 'af41'. See doc/ip-tos.txt.\n", v->lineno);
+		} else if (!strcasecmp(v->name, "tos_text")) {
+			if (ast_str2tos(v->value, &global_tos_text))
+				ast_log(LOG_WARNING, "Invalid tos_text value at line %d, recommended value is 'af41'. See doc/ip-tos.txt.\n", v->lineno);
 		} else if (!strcasecmp(v->name, "bindport")) {
 			if (sscanf(v->value, "%d", &ourport) == 1) {
 				bindaddr.sin_port = htons(ourport);
@@ -17208,8 +17518,33 @@ static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struc
 	return res;
 }
 
+/*! \brief Returns null if we can't reinvite text (part of RTP interface) */
+static enum ast_rtp_get_result sip_get_trtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
+{
+	struct sip_pvt *p = NULL;
+	enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
+	
+	if (!(p = chan->tech_pvt))
+		return AST_RTP_GET_FAILED;
+
+	sip_pvt_lock(p);
+	if (!(p->trtp)) {
+		sip_pvt_unlock(p);
+		return AST_RTP_GET_FAILED;
+	}
+
+	*rtp = p->trtp;
+
+	if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE))
+		res = AST_RTP_TRY_NATIVE;
+
+	sip_pvt_unlock(p);
+
+	return res;
+}
+
 /*! \brief Set the RTP peer for this call */
-static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
+static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
 {
 	struct sip_pvt *p;
 	int changed = 0;
@@ -17249,6 +17584,12 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struc
 		memset(&p->vredirip, 0, sizeof(p->vredirip));
 		changed = 1;
 	}
+	if (trtp) {
+		changed |= ast_rtp_get_peer(trtp, &p->tredirip);
+	} else if (p->tredirip.sin_addr.s_addr || ntohs(p->tredirip.sin_port) != 0) {
+		memset(&p->tredirip, 0, sizeof(p->tredirip));
+		changed = 1;
+	}
 	if (codecs && (p->redircodecs != codecs)) {
 		p->redircodecs = codecs;
 		changed = 1;
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index f6f68ea1625d2169ff7922c570e24dd87f2de7e3..70b2caeba1439b66e2c2edef38b020b2cc5bb9b5 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -1731,7 +1731,7 @@ static enum ast_rtp_get_result skinny_get_rtp_peer(struct ast_channel *c, struct
 	return AST_RTP_TRY_NATIVE;
 }
 
-static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
+static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
 {
 	struct skinny_subchannel *sub;
 	sub = c->tech_pvt;
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index e9695940b2b15576935f7f4a939317624386feac..22a08120cb180d397e2077131f334d23380bbaee 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -155,7 +155,7 @@ extern "C" {
 #include "asterisk/compiler.h"
 
 
-#define AST_MAX_FDS		8
+#define AST_MAX_FDS		10
 /*
  * We have AST_MAX_FDS file descriptors in a channel.
  * Some of them have a fixed use:
@@ -297,6 +297,9 @@ struct ast_channel_tech {
 	/*! \brief Write a frame, in standard format */
 	int (* const write_video)(struct ast_channel *chan, struct ast_frame *frame);
 
+	/*! \brief Write a text frame, in standard format */
+	int (* const write_text)(struct ast_channel *chan, struct ast_frame *frame);
+
 	/*! \brief Find bridged channel */
 	struct ast_channel *(* const bridged_channel)(struct ast_channel *chan, struct ast_channel *bridge);
 
@@ -888,6 +891,14 @@ int ast_write(struct ast_channel *chan, struct ast_frame *frame);
  */
 int ast_write_video(struct ast_channel *chan, struct ast_frame *frame);
 
+/*! \brief Write text frame to a channel 
+ * This function writes the given frame to the indicated channel.
+ * \param chan destination channel of the frame
+ * \param frame frame that will be written
+ * \return It returns 1 on success, 0 if not implemented, and -1 on failure.
+ */
+int ast_write_text(struct ast_channel *chan, struct ast_frame *frame);
+
 /*! \brief Send empty audio to prime a channel driver */
 int ast_prod(struct ast_channel *chan);
 
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 8d376b4be3351704ff3822f6a163274ff4cc2a29..fa0b6f939a31f0eb044b5a9627bbc038785c9947 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -268,7 +268,7 @@ extern struct ast_frame ast_null_frame;
 #define AST_FORMAT_T140		(1 << 25)
 /*! Maximum text mask */
 #define AST_FORMAT_MAX_TEXT	(1 << 26)
-#define AST_FORMAT_TEXT_MASK   (((1 << 27)-1) & ~(AST_FORMAT_AUDIO_MASK) & ~(AST_FORMAT_VIDEO_MASK)))
+#define AST_FORMAT_TEXT_MASK   (((1 << 27)-1) & ~(AST_FORMAT_AUDIO_MASK) & ~(AST_FORMAT_VIDEO_MASK))
 
 enum ast_control_frame_type {
 	AST_CONTROL_HANGUP = 1,		/*!< Other end has hungup */
diff --git a/include/asterisk/rtp.h b/include/asterisk/rtp.h
index 85f3b19030c709873b6fb6ee12467b66cddae677..5eea063db869b0b218550a7c8b6e136c666d3d2b 100644
--- a/include/asterisk/rtp.h
+++ b/include/asterisk/rtp.h
@@ -75,8 +75,10 @@ struct ast_rtp_protocol {
 	enum ast_rtp_get_result (* const get_rtp_info)(struct ast_channel *chan, struct ast_rtp **rtp);
 	/*! Get RTP struct, or NULL if unwilling to transfer */
 	enum ast_rtp_get_result (* const get_vrtp_info)(struct ast_channel *chan, struct ast_rtp **rtp);
+	/*! Get RTP struct, or NULL if unwilling to transfer */
+	enum ast_rtp_get_result (* const get_trtp_info)(struct ast_channel *chan, struct ast_rtp **rtp);
 	/*! Set RTP peer */
-	int (* const set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer, struct ast_rtp *vpeer, int codecs, int nat_active);
+	int (* const set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer, struct ast_rtp *vpeer, struct ast_rtp *tpeer, int codecs, int nat_active);
 	int (* const get_codec)(struct ast_channel *chan);
 	const char * const type;
 	AST_LIST_ENTRY(ast_rtp_protocol) list;
diff --git a/main/channel.c b/main/channel.c
index 94e21d0823419647c0af51cd53781e56a29b4352..0405a7ab5a532cfa4efdf4d8aa02761bb689bf58 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -2569,8 +2569,13 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 		CHECK_BLOCKING(chan);
 		break;
 	case AST_FRAME_TEXT:
-		res = (chan->tech->send_text == NULL) ? 0 :
-			chan->tech->send_text(chan, (char *) fr->data);
+		if (fr->subclass == AST_FORMAT_T140) {
+			res = (chan->tech->write_text == NULL) ? 0 :
+				chan->tech->write_text(chan, fr);
+		} else {
+			res = (chan->tech->send_text == NULL) ? 0 :
+				chan->tech->send_text(chan, (char *) fr->data);
+		}
 		break;
 	case AST_FRAME_HTML:
 		res = (chan->tech->send_html == NULL) ? 0 :
@@ -2898,6 +2903,7 @@ struct ast_channel *ast_request(const char *type, int format, void *data, int *c
 	int res;
 	int foo;
 	int videoformat = format & AST_FORMAT_VIDEO_MASK;
+	int textformat = format & AST_FORMAT_TEXT_MASK;
 
 	if (!cause)
 		cause = &foo;
@@ -2924,7 +2930,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 | videoformat, data, cause)))
+		if (!(c = chan->tech->requester(type, capabilities | videoformat | textformat, data, cause)))
 			return NULL;
 		
 		/* no need to generate a Newchannel event here; it is done in the channel_alloc call */
diff --git a/main/rtp.c b/main/rtp.c
index 21310e1e7706f1839c71e5ad1dc82f022ca4254c..afb5c256afb90b8029d3bea6df76e3a0527692d3 100644
--- a/main/rtp.c
+++ b/main/rtp.c
@@ -118,6 +118,8 @@ struct ast_rtp {
 	unsigned int lastrxts;
 	unsigned int lastividtimestamp;
 	unsigned int lastovidtimestamp;
+	unsigned int lastitexttimestamp;
+	unsigned int lastotexttimestamp;
 	unsigned int lasteventseqn;
 	int lastrxseqno;                /*!< Last received sequence number */
 	unsigned short seedrxseqno;     /*!< What sequence number did they start with?*/
@@ -1333,7 +1335,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
 		return f ? f : &ast_null_frame;
 	}
 	rtp->lastrxformat = rtp->f.subclass = rtpPT.code;
-	rtp->f.frametype = (rtp->f.subclass < AST_FORMAT_MAX_AUDIO) ? AST_FRAME_VOICE : AST_FRAME_VIDEO;
+	rtp->f.frametype = (rtp->f.subclass < AST_FORMAT_MAX_AUDIO) ? AST_FRAME_VOICE : (rtp->f.subclass < AST_FORMAT_MAX_VIDEO) ? AST_FRAME_VIDEO : AST_FRAME_TEXT;
 
 	if (!rtp->lastrxts)
 		rtp->lastrxts = timestamp;
@@ -1357,7 +1359,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
 		rtp->f.ts = timestamp / 8;
 		rtp->f.len = rtp->f.samples / 8;
 		rtp->f.seqno = seqno;
-	} else {
+	} else if(rtp->f.subclass < AST_FORMAT_MAX_VIDEO) {
 		/* Video -- samples is # of samples vs. 90000 */
 		if (!rtp->lastividtimestamp)
 			rtp->lastividtimestamp = timestamp;
@@ -1367,7 +1369,14 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
 		rtp->f.delivery.tv_usec = 0;
 		if (mark)
 			rtp->f.subclass |= 0x1;
-		
+	} else {
+		/* TEXT -- samples is # of samples vs. 1000 */
+		if (!rtp->lastitexttimestamp)
+			rtp->lastitexttimestamp = timestamp;
+		rtp->f.samples = timestamp - rtp->lastitexttimestamp;
+		rtp->lastitexttimestamp = timestamp;
+		rtp->f.delivery.tv_sec = 0;
+		rtp->f.delivery.tv_usec = 0;
 	}
 	rtp->f.src = "RTP";
 	return &rtp->f;
@@ -1524,9 +1533,10 @@ int ast_rtp_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
 	// dest = c0, src = c1
 	struct ast_rtp *destp = NULL, *srcp = NULL;		/* Audio RTP Channels */
 	struct ast_rtp *vdestp = NULL, *vsrcp = NULL;		/* Video RTP channels */
+	struct ast_rtp *tdestp = NULL, *tsrcp = NULL;		/* Text RTP channels */
 	struct ast_rtp_protocol *destpr = NULL, *srcpr = NULL;
-	enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED, video_dest_res = AST_RTP_GET_FAILED;
-	enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED, video_src_res = AST_RTP_GET_FAILED;
+	enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED, video_dest_res = AST_RTP_GET_FAILED, text_dest_res = AST_RTP_GET_FAILED;
+	enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED, video_src_res = AST_RTP_GET_FAILED, text_src_res = AST_RTP_GET_FAILED;
 	int srccodec, nat_active = 0;
 
 	/* Lock channels */
@@ -1560,12 +1570,14 @@ int ast_rtp_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
 		return -1;
 	}
 
-	/* Get audio and video interface (if native bridge is possible) */
+	/* Get audio, video  and text interface (if native bridge is possible) */
 	audio_dest_res = destpr->get_rtp_info(c0, &destp);
 	video_dest_res = destpr->get_vrtp_info ? destpr->get_vrtp_info(c0, &vdestp) : AST_RTP_GET_FAILED;
+	text_dest_res = destpr->get_trtp_info ? destpr->get_trtp_info(c0, &tdestp) : AST_RTP_GET_FAILED;
 	if (srcpr) {
 		audio_src_res = srcpr->get_rtp_info(c1, &srcp);
 		video_src_res = srcpr->get_vrtp_info ? srcpr->get_vrtp_info(c1, &vsrcp) : AST_RTP_GET_FAILED;
+		text_src_res = srcpr->get_trtp_info ? srcpr->get_trtp_info(c1, &tsrcp) : AST_RTP_GET_FAILED;
 	}
 
 	/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
@@ -1586,7 +1598,7 @@ int ast_rtp_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
 	if (srcp && (srcp->nat || ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
 		nat_active = 1;
 	/* Bridge media early */
-	if (destpr->set_rtp_peer(c0, srcp, vsrcp, srccodec, nat_active))
+	if (destpr->set_rtp_peer(c0, srcp, vsrcp, tsrcp, srccodec, nat_active))
 		ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
 	ast_channel_unlock(c0);
 	if (c1)
@@ -1600,9 +1612,10 @@ int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, i
 {
 	struct ast_rtp *destp = NULL, *srcp = NULL;		/* Audio RTP Channels */
 	struct ast_rtp *vdestp = NULL, *vsrcp = NULL;		/* Video RTP channels */
+	struct ast_rtp *tdestp = NULL, *tsrcp = NULL;		/* Text RTP channels */
 	struct ast_rtp_protocol *destpr = NULL, *srcpr = NULL;
-	enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED, video_dest_res = AST_RTP_GET_FAILED;
-	enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED, video_src_res = AST_RTP_GET_FAILED; 
+	enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED, video_dest_res = AST_RTP_GET_FAILED, text_dest_res = AST_RTP_GET_FAILED;
+	enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED, video_src_res = AST_RTP_GET_FAILED, text_src_res = AST_RTP_GET_FAILED; 
 	int srccodec;
 
 	/* Lock channels */
@@ -1632,8 +1645,10 @@ int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, i
 	/* Get audio and video interface (if native bridge is possible) */
 	audio_dest_res = destpr->get_rtp_info(dest, &destp);
 	video_dest_res = destpr->get_vrtp_info ? destpr->get_vrtp_info(dest, &vdestp) : AST_RTP_GET_FAILED;
+	text_dest_res = destpr->get_trtp_info ? destpr->get_trtp_info(dest, &tdestp) : AST_RTP_GET_FAILED;
 	audio_src_res = srcpr->get_rtp_info(src, &srcp);
 	video_src_res = srcpr->get_vrtp_info ? srcpr->get_vrtp_info(src, &vsrcp) : AST_RTP_GET_FAILED;
+	text_src_res = srcpr->get_trtp_info ? srcpr->get_trtp_info(src, &tsrcp) : AST_RTP_GET_FAILED;
 
 	/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
 	if (audio_dest_res != AST_RTP_TRY_NATIVE || audio_src_res != AST_RTP_TRY_NATIVE) {
@@ -1645,13 +1660,15 @@ int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, i
 	ast_rtp_pt_copy(destp, srcp);
 	if (vdestp && vsrcp)
 		ast_rtp_pt_copy(vdestp, vsrcp);
+	if (tdestp && tsrcp)
+		ast_rtp_pt_copy(tdestp, tsrcp);
 	if (srcpr->get_codec)
 		srccodec = srcpr->get_codec(src);
 	else
 		srccodec = 0;
 	if (media) {
 		/* Bridge early */
-		if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
+		if (destpr->set_rtp_peer(dest, srcp, vsrcp, tsrcp, srccodec, ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
 			ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", dest->name, src->name);
 	}
 	ast_channel_unlock(dest);
@@ -2080,6 +2097,8 @@ void ast_rtp_reset(struct ast_rtp *rtp)
 	rtp->lastrxts = 0;
 	rtp->lastividtimestamp = 0;
 	rtp->lastovidtimestamp = 0;
+	rtp->lastitexttimestamp = 0;
+	rtp->lastotexttimestamp = 0;
 	rtp->lasteventseqn = 0;
 	rtp->lasteventendseqn = 0;
 	rtp->lasttxformat = 0;
@@ -2627,7 +2646,7 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
 				mark = 1;
 			}
 		}
-	} else {
+	} else if(f->subclass < AST_FORMAT_MAX_VIDEO) {
 		mark = f->subclass & 0x1;
 		pred = rtp->lastovidtimestamp + f->samples;
 		/* Re-calculate last TS */
@@ -2643,6 +2662,21 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
 				rtp->lastovidtimestamp = rtp->lastts;
 			}
 		}
+	} else {
+		pred = rtp->lastotexttimestamp + f->samples;
+		/* Re-calculate last TS */
+		rtp->lastts = rtp->lastts + ms * 90;
+		/* If it's close to our prediction, go for it */
+		if (ast_tvzero(f->delivery)) {
+			if (abs(rtp->lastts - pred) < 7200) {
+				rtp->lastts = pred;
+				rtp->lastotexttimestamp += f->samples;
+			} else {
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG, "Difference is %d, ms is %d (%d), pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, f->samples);
+				rtp->lastotexttimestamp = rtp->lastts;
+			}
+		}
 	}
 	/* If the timestamp for non-digit packets has moved beyond the timestamp
 	   for digits, update the digit timestamp.
@@ -2736,11 +2770,12 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
 		return 0;
 	
 	/* 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 and video\n");
+	if ((_f->frametype != AST_FRAME_VOICE) && (_f->frametype != AST_FRAME_VIDEO) && (_f->frametype != AST_FRAME_TEXT)) {
+		ast_log(LOG_WARNING, "RTP can only send voice, video and text\n");
 		return -1;
 	}
 
+	/* The bottom bit of a video subclass contains the marker bit */
 	subclass = _f->subclass;
 	if (_f->frametype == AST_FRAME_VIDEO)
 		subclass &= ~0x1;
@@ -2825,29 +2860,33 @@ int ast_rtp_proto_register(struct ast_rtp_protocol *proto)
 }
 
 /*! \brief Bridge loop for true native bridge (reinvite) */
-static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp *p0, struct ast_rtp *p1, struct ast_rtp *vp0, struct ast_rtp *vp1, struct ast_rtp_protocol *pr0, struct ast_rtp_protocol *pr1, int codec0, int codec1, int timeoutms, int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
+static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp *p0, struct ast_rtp *p1, struct ast_rtp *vp0, struct ast_rtp *vp1, struct ast_rtp *tp0, struct ast_rtp *tp1, struct ast_rtp_protocol *pr0, struct ast_rtp_protocol *pr1, int codec0, int codec1, int timeoutms, int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
 {
 	struct ast_frame *fr = NULL;
 	struct ast_channel *who = NULL, *other = NULL, *cs[3] = {NULL, };
 	int oldcodec0 = codec0, oldcodec1 = codec1;
-	struct sockaddr_in ac1 = {0,}, vac1 = {0,}, ac0 = {0,}, vac0 = {0,};
-	struct sockaddr_in t1 = {0,}, vt1 = {0,}, t0 = {0,}, vt0 = {0,};
+	struct sockaddr_in ac1 = {0,}, vac1 = {0,}, tac1 = {0,}, ac0 = {0,}, vac0 = {0,}, tac0 = {0,};
+	struct sockaddr_in t1 = {0,}, vt1 = {0,}, tt1 = {0,}, t0 = {0,}, vt0 = {0,}, tt0 = {0,};
 	
 	/* Set it up so audio goes directly between the two endpoints */
 
 	/* Test the first channel */
-	if (!(pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))) {
+	if (!(pr0->set_rtp_peer(c0, p1, vp1, tp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))) {
 		ast_rtp_get_peer(p1, &ac1);
 		if (vp1)
 			ast_rtp_get_peer(vp1, &vac1);
+		if (tp1)
+			ast_rtp_get_peer(tp1, &tac1);
 	} else
 		ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
 	
 	/* Test the second channel */
-	if (!(pr1->set_rtp_peer(c1, p0, vp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))) {
+	if (!(pr1->set_rtp_peer(c1, p0, vp0, tp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))) {
 		ast_rtp_get_peer(p0, &ac0);
 		if (vp0)
 			ast_rtp_get_peer(vp0, &vac0);
+		if (tp0)
+			ast_rtp_get_peer(tp0, &tac0);
 	} else
 		ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c1->name, c0->name);
 
@@ -2867,10 +2906,10 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
 			if (option_debug)
 				ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n");
 			if (c0->tech_pvt == pvt0)
-				if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0))
+				if (pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0))
 					ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
 			if (c1->tech_pvt == pvt1)
-				if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0))
+				if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0))
 					ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
 			return AST_BRIDGE_RETRY;
 		}
@@ -2879,44 +2918,56 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
 		ast_rtp_get_peer(p1, &t1);
 		if (vp1)
 			ast_rtp_get_peer(vp1, &vt1);
+		if (tp1)
+			ast_rtp_get_peer(tp1, &tt1);
 		if (pr1->get_codec)
 			codec1 = pr1->get_codec(c1);
 		ast_rtp_get_peer(p0, &t0);
 		if (vp0)
 			ast_rtp_get_peer(vp0, &vt0);
+		if (tp0)
+			ast_rtp_get_peer(tp0, &tt0);
 		if (pr0->get_codec)
 			codec0 = pr0->get_codec(c0);
 		if ((inaddrcmp(&t1, &ac1)) ||
 		    (vp1 && inaddrcmp(&vt1, &vac1)) ||
+		    (tp1 && inaddrcmp(&tt1, &tac1)) ||
 		    (codec1 != oldcodec1)) {
 			if (option_debug > 1) {
 				ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n",
 					c1->name, ast_inet_ntoa(t1.sin_addr), ntohs(t1.sin_port), codec1);
 				ast_log(LOG_DEBUG, "Oooh, '%s' changed end vaddress to %s:%d (format %d)\n",
 					c1->name, ast_inet_ntoa(vt1.sin_addr), ntohs(vt1.sin_port), codec1);
+				ast_log(LOG_DEBUG, "Oooh, '%s' changed end taddress to %s:%d (format %d)\n",
+					c1->name, ast_inet_ntoa(tt1.sin_addr), ntohs(tt1.sin_port), codec1);
 				ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n",
 					c1->name, ast_inet_ntoa(ac1.sin_addr), ntohs(ac1.sin_port), oldcodec1);
 				ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n",
 					c1->name, ast_inet_ntoa(vac1.sin_addr), ntohs(vac1.sin_port), oldcodec1);
+				ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n",
+					c1->name, ast_inet_ntoa(tac1.sin_addr), ntohs(tac1.sin_port), oldcodec1);
 			}
-			if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))
+			if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, tt1.sin_addr.s_addr ? tp1 : NULL, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))
 				ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
 			memcpy(&ac1, &t1, sizeof(ac1));
 			memcpy(&vac1, &vt1, sizeof(vac1));
+			memcpy(&tac1, &tt1, sizeof(tac1));
 			oldcodec1 = codec1;
 		}
 		if ((inaddrcmp(&t0, &ac0)) ||
-		    (vp0 && inaddrcmp(&vt0, &vac0))) {
+		    (vp0 && inaddrcmp(&vt0, &vac0)) ||
+		    (tp0 && inaddrcmp(&tt0, &tac0))) {
 			if (option_debug > 1) {
 				ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n",
 					c0->name, ast_inet_ntoa(t0.sin_addr), ntohs(t0.sin_port), codec0);
 				ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n",
 					c0->name, ast_inet_ntoa(ac0.sin_addr), ntohs(ac0.sin_port), oldcodec0);
 			}
-			if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
+			if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, tt0.sin_addr.s_addr ? tp0 : NULL, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
 				ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
 			memcpy(&ac0, &t0, sizeof(ac0));
 			memcpy(&vac0, &vt0, sizeof(vac0));
+			memcpy(&tac0, &tt0, sizeof(tac0));
 			oldcodec0 = codec0;
 		}
 
@@ -2941,10 +2992,10 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
 			if (option_debug)
 				ast_log(LOG_DEBUG, "Oooh, got a %s\n", fr ? "digit" : "hangup");
 			if (c0->tech_pvt == pvt0)
-				if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0))
+				if (pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0))
 					ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
 			if (c1->tech_pvt == pvt1)
-				if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0))
+				if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0))
 					ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
 			return AST_BRIDGE_COMPLETE;
 		} else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
@@ -2954,15 +3005,15 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
 				if (fr->subclass == AST_CONTROL_HOLD) {
 					/* If we someone went on hold we want the other side to reinvite back to us */
 					if (who == c0)
-						pr1->set_rtp_peer(c1, NULL, NULL, 0, 0);
+						pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0);
 					else
-						pr0->set_rtp_peer(c0, NULL, NULL, 0, 0);
+						pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0);
 				} else if (fr->subclass == AST_CONTROL_UNHOLD) {
 					/* If they went off hold they should go back to being direct */
 					if (who == c0)
-						pr1->set_rtp_peer(c1, p0, vp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE));
+						pr1->set_rtp_peer(c1, p0, vp0, tp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE));
 					else
-						pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE));
+						pr0->set_rtp_peer(c0, p1, vp1, tp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE));
 				}
 				ast_indicate_data(other, fr->subclass, fr->data, fr->datalen);
 				ast_frfree(fr);
@@ -3260,9 +3311,10 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel
 {
 	struct ast_rtp *p0 = NULL, *p1 = NULL;		/* Audio RTP Channels */
 	struct ast_rtp *vp0 = NULL, *vp1 = NULL;	/* Video RTP channels */
+	struct ast_rtp *tp0 = NULL, *tp1 = NULL;	/* Text RTP channels */
 	struct ast_rtp_protocol *pr0 = NULL, *pr1 = NULL;
-	enum ast_rtp_get_result audio_p0_res = AST_RTP_GET_FAILED, video_p0_res = AST_RTP_GET_FAILED;
-	enum ast_rtp_get_result audio_p1_res = AST_RTP_GET_FAILED, video_p1_res = AST_RTP_GET_FAILED;
+	enum ast_rtp_get_result audio_p0_res = AST_RTP_GET_FAILED, video_p0_res = AST_RTP_GET_FAILED, text_p0_res = AST_RTP_GET_FAILED;
+	enum ast_rtp_get_result audio_p1_res = AST_RTP_GET_FAILED, video_p1_res = AST_RTP_GET_FAILED, text_p1_res = AST_RTP_GET_FAILED;
 	enum ast_bridge_result res = AST_BRIDGE_FAILED;
 	int codec0 = 0, codec1 = 0;
 	void *pvt0 = NULL, *pvt1 = NULL;
@@ -3296,8 +3348,10 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel
 	/* Get audio and video interface (if native bridge is possible) */
 	audio_p0_res = pr0->get_rtp_info(c0, &p0);
 	video_p0_res = pr0->get_vrtp_info ? pr0->get_vrtp_info(c0, &vp0) : AST_RTP_GET_FAILED;
+	text_p0_res = pr0->get_trtp_info ? pr0->get_trtp_info(c0, &vp0) : AST_RTP_GET_FAILED;
 	audio_p1_res = pr1->get_rtp_info(c1, &p1);
 	video_p1_res = pr1->get_vrtp_info ? pr1->get_vrtp_info(c1, &vp1) : AST_RTP_GET_FAILED;
+	text_p1_res = pr1->get_trtp_info ? pr1->get_trtp_info(c1, &vp1) : AST_RTP_GET_FAILED;
 
 	/* If we are carrying video, and both sides are not reinviting... then fail the native bridge */
 	if (video_p0_res != AST_RTP_GET_FAILED && (audio_p0_res != AST_RTP_TRY_NATIVE || video_p0_res != AST_RTP_TRY_NATIVE))
@@ -3384,7 +3438,7 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel
 	} else {
 		if (option_verbose > 2) 
 			ast_verbose(VERBOSE_PREFIX_3 "Native bridging %s and %s\n", c0->name, c1->name);
-		res = bridge_native_loop(c0, c1, p0, p1, vp0, vp1, pr0, pr1, codec0, codec1, timeoutms, flags, fo, rc, pvt0, pvt1);
+		res = bridge_native_loop(c0, c1, p0, p1, vp0, vp1, tp0, tp1, pr0, pr1, codec0, codec1, timeoutms, flags, fo, rc, pvt0, pvt1);
 	}
 
 	return res;