[asterisk-commits] oej: branch oej/videocaps r47884 - in /team/oej/videocaps: apps/ channels/ co...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue Nov 21 07:15:40 MST 2006


Author: oej
Date: Tue Nov 21 08:15:40 2006
New Revision: 47884

URL: http://svn.digium.com/view/asterisk?view=rev&rev=47884
Log:
This branch includes a lot of different pieces of code by John Martin, Aupix.
- Video capabilities handling
- T.140 text support in RTP (realtime text)
- Fast update requests in rtcp or xml

The patches outside of videocaps will be moved out and separated at a later stage,
but right now we need to import all and automerge it up to current trunk

Modified:
    team/oej/videocaps/apps/app_dial.c
    team/oej/videocaps/apps/app_queue.c
    team/oej/videocaps/channels/chan_agent.c
    team/oej/videocaps/channels/chan_gtalk.c
    team/oej/videocaps/channels/chan_h323.c
    team/oej/videocaps/channels/chan_mgcp.c
    team/oej/videocaps/channels/chan_sip.c
    team/oej/videocaps/channels/chan_skinny.c
    team/oej/videocaps/configs/sip.conf.sample
    team/oej/videocaps/formats/format_h263.c
    team/oej/videocaps/include/asterisk/channel.h
    team/oej/videocaps/include/asterisk/frame.h
    team/oej/videocaps/include/asterisk/rtp.h
    team/oej/videocaps/main/channel.c
    team/oej/videocaps/main/cli.c
    team/oej/videocaps/main/frame.c
    team/oej/videocaps/main/rtp.c

Modified: team/oej/videocaps/apps/app_dial.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/apps/app_dial.c?view=diff&rev=47884&r1=47883&r2=47884
==============================================================================
--- team/oej/videocaps/apps/app_dial.c (original)
+++ team/oej/videocaps/apps/app_dial.c Tue Nov 21 08:15:40 2006
@@ -456,8 +456,10 @@
 			c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
 			if (!c)
 				ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
-			else
+			else {
 				ast_channel_inherit_variables(in, o->chan);
+				ast_set_capabilities(o->chan, &in->channelcaps);
+			}
 		}
 	} else {
 		if (option_verbose > 2)
@@ -699,6 +701,10 @@
 				case AST_CONTROL_FLASH:
 					/* Ignore going off hook and flash */
 					break;
+				case AST_CONTROL_CAPABILITY:
+			  	if (option_verbose > 2)
+			  		ast_verbose(VERBOSE_PREFIX_3 "Call on %s is indicating caps %d\n", o->chan->name, f->datalen);
+			  	ast_indicate_data(in, AST_CONTROL_CAPABILITY, f->data, f->datalen);
 				case -1:
 					if (!ast_test_flag(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
 						if (option_verbose > 2)
@@ -709,7 +715,8 @@
 					break;
 				default:
 					if (option_debug)
-						ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
+					  ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
+					 ast_verbose("Dunno what to do with control type %d\n", f->subclass);
 				}
 			} else if (single) {
 				/* XXX are we sure the logic is correct ? or we should just switch on f->frametype ? */
@@ -785,6 +792,7 @@
 			if (single && (f->frametype == AST_FRAME_CONTROL) && 
 				((f->subclass == AST_CONTROL_HOLD) || 
 				 (f->subclass == AST_CONTROL_UNHOLD) || 
+				 (f->subclass == AST_CONTROL_CAPABILITY) || 
 				 (f->subclass == AST_CONTROL_VIDUPDATE))) {
 				if (option_verbose > 2)
 					ast_verbose(VERBOSE_PREFIX_3 "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name);
@@ -1287,6 +1295,7 @@
 				chan->hangupcause = cause;
 			continue;
 		}
+		ast_set_capabilities(tmp->chan, &chan->channelcaps);
 		pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", numsubst);
 		if (!ast_strlen_zero(tmp->chan->call_forward)) {
 			char tmpchan[256];
@@ -1317,8 +1326,10 @@
 				}
 				if (!tmp->chan)
 					ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
-				else
+				else {
 					ast_channel_inherit_variables(chan, tmp->chan);
+					ast_set_capabilities(tmp->chan, &chan->channelcaps);
+				}
 			} else {
 				if (option_verbose > 2)
 					ast_verbose(VERBOSE_PREFIX_3 "Too many forwards from %s\n", tmp->chan->name);

Modified: team/oej/videocaps/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/apps/app_queue.c?view=diff&rev=47884&r1=47883&r2=47884
==============================================================================
--- team/oej/videocaps/apps/app_queue.c (original)
+++ team/oej/videocaps/apps/app_queue.c Tue Nov 21 08:15:40 2006
@@ -1686,6 +1686,7 @@
 	tmp->chan->adsicpe = qe->chan->adsicpe;
 
 	/* Place the call, but don't wait on the answer */
+	pbx_builtin_setvar_helper(tmp->chan, "MEMBERNAME", tmp->member->membername);
 	if ((res = ast_call(tmp->chan, location, 0))) {
 		/* Again, keep going even if there's an error */
 		if (option_debug)
@@ -2005,6 +2006,7 @@
 						if (o->chan->cid.cid_rdnis)
 							free(o->chan->cid.cid_rdnis);
 						o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
+						pbx_builtin_setvar_helper(o->chan, "MEMBERNAME", o->member->membername);
 						if (ast_call(o->chan, tmpchan, 0)) {
 							ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
 							do_hang(o);

Modified: team/oej/videocaps/channels/chan_agent.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/channels/chan_agent.c?view=diff&rev=47884&r1=47883&r2=47884
==============================================================================
--- team/oej/videocaps/channels/chan_agent.c (original)
+++ team/oej/videocaps/channels/chan_agent.c Tue Nov 21 08:15:40 2006
@@ -450,9 +450,9 @@
 				status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
 				if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
 					long logintime = time(NULL) - p->loginstart;
-					p->loginstart = 0;
 					ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);
 					agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
+					p->loginstart = 0;
 				}
 				ast_hangup(p->chan);
 				if (p->wrapuptime && p->acknowledged)
@@ -755,9 +755,9 @@
 				status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
 				if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
 					long logintime = time(NULL) - p->loginstart;
-					p->loginstart = 0;
 					ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
 					agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
+					p->loginstart = 0;
 				}
 				/* Recognize the hangup and pass it along immediately */
 				ast_hangup(p->chan);
@@ -767,9 +767,9 @@
 				ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
 			if (howlong  && p->autologoff && (howlong > p->autologoff)) {
 				long logintime = time(NULL) - p->loginstart;
-				p->loginstart = 0;
 				ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
 				agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
+				p->loginstart = 0;
 			}
 		} else if (p->dead) {
 			ast_channel_lock(p->chan);
@@ -1464,6 +1464,7 @@
 {
 	char *tmp = NULL;
 	char agent[AST_MAX_AGENT];
+	char temp_time[32];
 
 	if (!ast_strlen_zero(logcommand))
 		tmp = logcommand;
@@ -1489,7 +1490,9 @@
 				p->agent, tmp, loginchan, logintime);
 	}
 
-	ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
+	snprintf(temp_time, sizeof(temp_time), "%ld.0", (long)p->loginstart);
+	ast_verbose("Logging off with time of %s\n", temp_time);
+	ast_queue_log("NONE", temp_time, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
 	set_agentbycallerid(p->logincallerid, NULL);
 	p->loginchan[0] ='\0';
 	p->logincallerid[0] = '\0';
@@ -1515,8 +1518,8 @@
 			}
 			ret = 0; /* found an agent => return 0 */
 			logintime = time(NULL) - p->loginstart;
+			agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
 			p->loginstart = 0;
-			agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
 			break;
 		}
 	}
@@ -1687,7 +1690,10 @@
 			agent_status = 1;
 			online_agents++;
 		} else if (!ast_strlen_zero(p->loginchan)) {
-			snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
+			if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
+				snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
+			else 
+				snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
 			talkingto[0] = '\0';
 			agent_status = 1;
 			online_agents++;
@@ -1710,7 +1716,73 @@
 	return RESULT_SUCCESS;
 }
 
-
+static int agent_show(int fd, int argc, char **argv)
+{
+	struct agent_pvt *p;
+	struct tm tm;
+	char dateformat[256] = "%b %e %T";		/* Original Asterisk Format */
+	char date[256];
+	int seconds;
+	
+	if (argc != 3)
+		return RESULT_SHOWUSAGE;
+
+	if (!argv[2]) 
+		return RESULT_FAILURE;
+	
+	AST_LIST_LOCK(&agents);
+	AST_LIST_TRAVERSE(&agents, p, list) {
+		/* Look for either the agent ID or... */
+		if (!strncasecmp(p->agent, argv[2], strlen(p->agent)))
+			break;
+		/* ... the agent name */
+		if (!strncasecmp(p->name, argv[2], strlen(p->name)))
+			break;
+	}
+	AST_LIST_UNLOCK(&agents);
+	
+	if (!p)	{
+		ast_verbose("Couldn't find agent %s\n", argv[2]);
+		return RESULT_FAILURE;
+	}
+	
+	ast_cli(fd, "Lock:          %08x\n",(unsigned int)&p->lock);              
+	ast_cli(fd, "AgentID:       %s\n", p->agent);
+	ast_cli(fd, "Password:      %s\n", p->password);
+	ast_cli(fd, "AgentName:     %s\n", p->name);
+
+	localtime_r(&p->loginstart, &tm);
+	strftime(date, sizeof(date), dateformat, &tm);
+	ast_cli(fd, "LoggedInAt:    %s\n", p->loginstart ? date : "Not Logged In");
+
+	ast_cli(fd, "Dead:          %d\n", p->dead);
+	ast_cli(fd, "Pending:       %d\n", p->pending);
+	ast_cli(fd, "AboutToGrab:   %d\n", p->abouttograb);
+	ast_cli(fd, "AutoLogoff:    %d seconds\n", p->autologoff);
+	ast_cli(fd, "AckCall:       %d\n", p->ackcall);
+
+	localtime_r(&p->start, &tm);
+	strftime(date, sizeof(date), dateformat, &tm);
+	ast_cli(fd, "Start:         %s\n", p->start ? date : "Not in a call");
+	ast_cli(fd, "In a call for: %ld seconds\n", p->start ? time(NULL) - p->start : 0);
+
+	seconds = (p->lastdisc.tv_sec !=0) ? ast_tvdiff_ms(p->lastdisc, ast_tvnow())/1000 : 0;
+	ast_cli(fd, "Available In:  %d\n", seconds > 0 ? seconds : 0);
+	ast_cli(fd, "WrapupTime:    %d seconds\n", p->wrapuptime/1000);
+	//ast_group_t group
+	ast_cli(fd, "Group:         %08x\n", (unsigned int)p->group);
+	ast_cli(fd, "Acknowledged:  %d\n", p->acknowledged);
+	ast_cli(fd, "MOH:           %s\n", p->moh);
+	ast_cli(fd, "App_Lock:      %08x\n", (unsigned int)&p->app_lock);
+	//volatile pthread_t owning_app
+	//volatile int app_sleep_cond
+	ast_cli(fd, "Owner's name:  %s\n", p->owner ? p->owner->name : "none");
+	ast_cli(fd, "LoginChannel:  %s\n", p->loginchan);
+	ast_cli(fd, "LoginCallerID: %s\n", p->logincallerid);
+	//struct ast_channel *chan
+
+	return RESULT_SUCCESS;
+}
 
 static char show_agents_usage[] = 
 "Usage: agent show\n"
@@ -1719,11 +1791,21 @@
 static char show_agents_online_usage[] =
 "Usage: agent show online\n"
 "	Provides a list of all online agents.\n";
+
+static char show_agent_usage[] =
+"Usage: show agent <agentid | agentname>\n"
+" Shows an agent's internals when given agentid or agentname.\n"
+"   show agent 2000\n"
+"   show agent \"John Smith\"\n";
 
 static char agent_logoff_usage[] =
 "Usage: agent logoff <channel> [soft]\n"
 "       Sets an agent as no longer logged in.\n"
 "       If 'soft' is specified, do not hangup existing calls.\n";
+
+static struct ast_cli_entry cli_show_agent = {
+	{ "show", "agent", NULL }, agent_show,
+	"Show agent internals", show_agent_usage, NULL };
 
 static struct ast_cli_entry cli_agents[] = {
 	{ { "agent", "show", NULL },
@@ -2000,9 +2082,8 @@
 								dump_agents();
 						} else {
 							logintime = time(NULL) - p->loginstart;
+							agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL);
 							p->loginstart = 0;
-
-							agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL);
 							if (option_verbose > 1)
 								ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
 						}
@@ -2480,6 +2561,7 @@
 	ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
 
 	/* CLI Commands */
+	ast_cli_register(&cli_show_agent);
 	ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
 
 	/* Dialplan Functions */
@@ -2504,6 +2586,7 @@
 	/* Unregister dialplan functions */
 	ast_custom_function_unregister(&agent_function);	
 	/* Unregister CLI commands */
+	ast_cli_unregister(&cli_show_agent);
 	ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
 	/* Unregister dialplan applications */
 	ast_unregister_application(app);

Modified: team/oej/videocaps/channels/chan_gtalk.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/channels/chan_gtalk.c?view=diff&rev=47884&r1=47883&r2=47884
==============================================================================
--- team/oej/videocaps/channels/chan_gtalk.c (original)
+++ team/oej/videocaps/channels/chan_gtalk.c Tue Nov 21 08:15:40 2006
@@ -186,7 +186,7 @@
 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);
 
@@ -538,7 +538,7 @@
 	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;
 

Modified: team/oej/videocaps/channels/chan_h323.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/channels/chan_h323.c?view=diff&rev=47884&r1=47883&r2=47884
==============================================================================
--- team/oej/videocaps/channels/chan_h323.c (original)
+++ team/oej/videocaps/channels/chan_h323.c Tue Nov 21 08:15:40 2006
@@ -1915,6 +1915,7 @@
 	return info;
 }
 
+#if 0
 /**
  * Definition taken from rtp.c for rtpPayloadType because we need it here.
  */
@@ -1922,6 +1923,7 @@
 	int isAstFormat;	/* whether the following code is an AST_FORMAT */
 	int code;
 };
+#endif
 
 /**
   * Call-back function passing remote ip/port information from H.323 to asterisk

Modified: team/oej/videocaps/channels/chan_mgcp.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/channels/chan_mgcp.c?view=diff&rev=47884&r1=47883&r2=47884
==============================================================================
--- team/oej/videocaps/channels/chan_mgcp.c (original)
+++ team/oej/videocaps/channels/chan_mgcp.c Tue Nov 21 08:15:40 2006
@@ -3959,7 +3959,7 @@
 		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;

Modified: team/oej/videocaps/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/videocaps/channels/chan_sip.c?view=diff&rev=47884&r1=47883&r2=47884
==============================================================================
--- team/oej/videocaps/channels/chan_sip.c (original)
+++ team/oej/videocaps/channels/chan_sip.c Tue Nov 21 08:15:40 2006
@@ -152,7 +152,6 @@
 #define TRUE     1
 #endif
 
-#define VIDEO_CODEC_MASK        0x1fc0000 /*!< Video codecs from H.261 thru AST_FORMAT_MAX_VIDEO */
 #ifndef IPTOS_MINCOST
 #define IPTOS_MINCOST           0x02
 #endif
@@ -497,6 +496,7 @@
 #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
@@ -504,11 +504,20 @@
 #define DEFAULT_AUTOCREATEPEER	FALSE
 #define DEFAULT_QUALIFY		FALSE
 #define DEFAULT_T1MIN		100		/*!< 100 MS for minimal roundtrip time */
-#define DEFAULT_MAX_CALL_BITRATE (384)		/*!< Max bitrate for video */
+#define DEFAULT_MAX_FRAMERATE (30)
+#define VIDEO_UPDATE_XML 1
+#define VIDEO_UPDATE_RTCP 2
+#define DEFAULT_VIDEO_UPDATE (VIDEO_UPDATE_XML)
 #ifndef DEFAULT_USERAGENT
 #define DEFAULT_USERAGENT "Asterisk PBX"	/*!< Default Useragent: header unless re-defined in sip.conf */
 #endif
 
+static int global_videoupdate = DEFAULT_VIDEO_UPDATE;
+/* We set default caps but make them invalid. 
+  If a rtpmap comes in the we set valid.
+	If a fmtp comes in then we overwrite with new values.
+	*/
+static struct ast_capabilities global_caps; 
 
 /* Default setttings are used as a channel setting and as a default when
    configuring devices */
@@ -523,7 +532,6 @@
 static char default_mohinterpret[MAX_MUSICCLASS];  /*!< Global setting for moh class to use when put on hold */
 static char default_mohsuggest[MAX_MUSICCLASS];	   /*!< Global setting for moh class to suggest when putting 
                                                     *   a bridged channel on hold */
-static int default_maxcallbitrate;	/*!< Maximum bitrate for call */
 static struct ast_codec_pref default_prefs;		/*!< Default codec prefs */
 
 /* Global settings only apply to the channel */
@@ -549,6 +557,7 @@
 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 */
@@ -779,9 +788,13 @@
 #define SIP_PAGE2_CALL_ONHOLD_ONEDIR	(1 << 23)	/*!< 23: One directional hold */
 #define SIP_PAGE2_CALL_ONHOLD_INACTIVE	(1 << 24)	/*!< 24: Inactive  */
 #define SIP_PAGE2_RFC2833_COMPENSATE    (1 << 25)
+#define SIP_PAGE2_DEBUG_CAPS		(1 << 27)	/*!< 27: Debug Caps  */
+#define SIP_PAGE2_NOTEXT		(1 << 28)	/*!< 28: Text not supported  */
+#define SIP_PAGE2_TEXTSUPPORT		(1 << 29)	/*!< 29: Global text enable */
+#define SIP_PAGE2_DEBUG_TEXT		(1 << 30)	/*!< 30: 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_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | SIP_PAGE2_TEXTSUPPORT)
 
 /* SIP packet flags */
 #define SIP_PKT_DEBUG		(1 << 0)	/*!< Debug this packet */
@@ -817,6 +830,8 @@
 #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_caps			ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CAPS)
+#define sipdebug_text			ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_TEXT)
 
 /*! \brief T38 States for a call */
 enum t38state {
@@ -941,10 +956,13 @@
 	int capability;				/*!< Special capability (codec) */
 	int jointcapability;			/*!< Supported capability at both ends (codecs) */
 	int peercapability;			/*!< Supported peer capability */
+	int videoupdate;			/*!< Defines which FU mechanism RTCP or INFO is used */	
+	struct ast_capabilities caps; /*!< Supported video capapbilities for this peer/user */
+	struct ast_capabilities jointcaps; /*!< Supported video capapbilities at both ends */
+	struct ast_capabilities peercaps; /*!< Video capapbilities taken from the sdp */
 	int prefcodec;				/*!< Preferred codec (outbound only) */
 	int noncodeccapability;			/*!< DTMF RFC2833 telephony-event */
 	int redircodecs;			/*!< Redirect codecs */
-	int maxcallbitrate;			/*!< Maximum Call Bitrate for Video Calls */	
 	struct t38properties t38;		/*!< T38 settings */
 	struct sockaddr_in udptlredirip;	/*!< Where our T.38 UDPTL should be going if not to us */
 	struct ast_udptl *udptl;		/*!< T.38 UDPTL session */
@@ -958,6 +976,7 @@
 	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 */
@@ -994,6 +1013,7 @@
 	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 */
@@ -1061,13 +1081,14 @@
 	struct ast_flags flags[2];	/*!< SIP_ flags */
 	int amaflags;			/*!< AMA flags for billing */
 	int callingpres;		/*!< Calling id presentation */
+  struct ast_capabilities caps;		/*!< User capability */
 	int capability;			/*!< Codec capability */
 	int inUse;			/*!< Number of calls in use */
 	int call_limit;			/*!< Limit of concurrent calls */
 	enum transfermodes allowtransfer;	/*! SIP Refer restriction scheme */
 	struct ast_ha *ha;		/*!< ACL setting */
 	struct ast_variable *chanvars;	/*!< Variables to set for channel created by user */
-	int maxcallbitrate;		/*!< Maximum Bitrate for a video call */
+  int videoupdate /*!< Defines use of XML or RTCP for video update */;
 	int autoframing;
 };
 
@@ -1110,6 +1131,7 @@
 	struct ast_flags flags[2];	/*!<  SIP_ flags */
 	int expire;			/*!<  When to expire this peer registration */
 	int capability;			/*!<  Codec capability */
+  struct ast_capabilities caps;		/*!< Codec capability */
 	int rtptimeout;			/*!<  RTP timeout */
 	int rtpholdtimeout;		/*!<  RTP Hold Timeout */
 	int rtpkeepalive;		/*!<  Send RTP packets for keepalive */
@@ -1117,7 +1139,7 @@
 	ast_group_t pickupgroup;	/*!<  Pickup group */
 	struct ast_dnsmgr_entry *dnsmgr;/*!<  DNS refresh manager for peer */
 	struct sockaddr_in addr;	/*!<  IP address of peer */
-	int maxcallbitrate;		/*!< Maximum Bitrate for a video call */
+  int videoupdate /*!< Defines use of XML or RTCP for video update */;
 	
 	/* Qualification */
 	struct sip_pvt *call;		/*!<  Call pointer */
@@ -1225,6 +1247,7 @@
 static int sip_answer(struct ast_channel *ast);
 static struct ast_frame *sip_read(struct ast_channel *ast);
 static int sip_write(struct ast_channel *ast, struct ast_frame *frame);
+static int sip_set_capabilities(struct ast_channel *ast, struct ast_capabilities *chancaps);
 static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
 static int sip_transfer(struct ast_channel *ast, const char *dest);
 static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
@@ -1298,7 +1321,11 @@
 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 int find_sdp(struct sip_request *req);
+static int process_h2613_fmtp(const char *fmtstr, struct ast_h2613_video_cap *vidcap, unsigned int framerate);
+static int process_h264_fmtp(const char *fmtstr, struct ast_h264_video_cap *vidcap, int framerate);
 static int process_sdp(struct sip_pvt *p, struct sip_request *req);
+static void ast_build_h2613_fmtp(char **buf, size_t *size, int rtp_code, struct ast_h2613_video_cap *video_cap);
+static void ast_build_h264_fmtp(char **buf, size_t *size, int rtp_code, struct ast_h264_video_cap *video_cap);
 static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
 			     char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
 			     int debug, int *min_packet_size);
@@ -1537,9 +1564,10 @@
 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);
 
@@ -1563,6 +1591,7 @@
 	.read = sip_read,
 	.write = sip_write,
 	.write_video = sip_write,
+	.write_text = sip_write,
 	.indicate = sip_indicate,
 	.transfer = sip_transfer,
 	.fixup = sip_fixup,
@@ -1571,6 +1600,7 @@
 	.bridge = ast_rtp_bridge,
 	.early_bridge = ast_rtp_early_bridge,
 	.send_text = sip_sendtext,
+	.set_capabilities = sip_set_capabilities,
 };
 
 /**--- some list management macros. **/
@@ -1587,6 +1617,7 @@
 	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,
 };
@@ -2679,6 +2710,11 @@
 			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.
@@ -2699,6 +2735,10 @@
 	if ((!ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) || !(dialog->capability & AST_FORMAT_VIDEO_MASK)) && dialog->vrtp) {
 		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)) {
@@ -2728,6 +2768,10 @@
 	if (dialog->vrtp) {
 		ast_rtp_setdtmf(dialog->vrtp, 0);
 		ast_rtp_setdtmfcompensate(dialog->vrtp, 0);
+	}
+	if (dialog->trtp) {
+		ast_rtp_setdtmf(dialog->trtp, 0);
+		ast_rtp_setdtmfcompensate(dialog->trtp, 0);
 	}
 
 	/* Set Frame packetization */
@@ -2775,8 +2819,9 @@
 	dialog->rtpholdtimeout = peer->rtpholdtimeout;
 	dialog->rtpkeepalive = peer->rtpkeepalive;
 	if (peer->call_limit)
-		ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT);
-	dialog->maxcallbitrate = peer->maxcallbitrate;
+	ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT);
+	ast_copy_capabilities(&dialog->caps, &peer->caps);
+	dialog->videoupdate = peer->videoupdate;
 	
 	return 0;
 }
@@ -2864,6 +2909,9 @@
 	struct ast_var_t *current;
 	const char *referer = NULL;   /* SIP refererer */	
 
+  if(sipdebug_caps)
+		ast_verbose("SIPCALL: entering with channel->nativeformats=%08x, p->capability=%08x, p->jointcaps=%08x\n", ast->nativeformats, p->capability, p->jointcapability);
+	
 	p = ast->tech_pvt;
 	if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
 		ast_log(LOG_WARNING, "sip_call called on %s, neither down nor reserved\n", ast->name);
@@ -2921,6 +2969,13 @@
 		return res;
 
 	p->callingpres = ast->cid.cid_pres;
+	if(sipdebug_caps)
+		ast_verbose("SIPCALL: channel->nativeformats=%08x, p->capability=%08x, p->jointcaps=%08x\n", ast->nativeformats, p->capability, p->jointcapability);
+	if (ast->channelcaps.maxcallbitrate > 0 && ast->channelcaps.maxcallbitrate < p->caps.maxcallbitrate) {
+		p->caps.maxcallbitrate = ast->channelcaps.maxcallbitrate;
+		if(sipdebug_caps)
+			ast_verbose("SIPCALL: Setting sip_pvt call rate to %d for %s in sip_call()\n", p->caps.maxcallbitrate, p->username);
+	}
 	p->jointcapability = ast_translate_available_formats(p->capability, p->prefcodec);
 	
 	/* If there are no audio formats left to offer, punt */
@@ -2997,6 +3052,8 @@
 		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)
@@ -3463,10 +3520,13 @@
 			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);
 
@@ -3476,11 +3536,15 @@
 						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. */
@@ -3595,6 +3659,23 @@
 				res = ast_rtp_write(p->vrtp, frame);
 			}
 			sip_pvt_unlock(p);
+		}
+		break;
+	case AST_FRAME_TEXT:
+		if (p) {
+			ast_mutex_lock(&p->lock);
+			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);
+			}
+			ast_mutex_unlock(&p->lock);
 		}
 		break;
 	case AST_FRAME_IMAGE:
@@ -3623,6 +3704,59 @@
 	return res;
 }
 
+/*! \brief  sip_set_capabilities: called when channel needs to have caps updated from another channel */
+/* When * is making an outgoing call, the confcaps will be set (sip_new has already been called) but
+   jointcaps and peer caps will be zero */
+/* On the REVERSE cap exchange we'll need to do a MIN(joint, chancap); */
+static int sip_set_capabilities(struct ast_channel *ast, struct ast_capabilities *chancaps)
+{
+	struct sip_pvt *p = ast->tech_pvt;
+	int res = 0;
+	
+  if(sipdebug_caps)
+	{
+		ast_verbose("Calling sip_set_capabilities for %s\n", ast->name);
+
+		if (chancaps->maxcallbitrate) {
+			ast_verbose("SET_CAPABILITIES: Chancaps (%s)\n",ast->name);
+			ast_dump_caps(chancaps);
+		}
+		if (p->jointcaps.maxcallbitrate) {
+			ast_verbose("SET_CAPABILITIES: Jointcaps (%s)\n",ast->name);
+			ast_dump_caps(&p->jointcaps);
+		}
+		if (p->peercaps.maxcallbitrate) {
+			ast_verbose("SET_CAPABILITIES: Peercaps (%s)\n",ast->name);
+			ast_dump_caps(&p->peercaps);
+		}
+		if (p->caps.maxcallbitrate) {
+			ast_verbose("SET_CAPABILITIES: Caps (%s)\n",ast->name);
+			ast_dump_caps(&p->caps);
+		}
+	}
+
+	/* Jointcaps will be zero on entry for outbound calls */
+	if (ast_are_caps_zero(&p->jointcaps)) {
+		ast_copy_capabilities(&p->jointcaps, chancaps);
+	} else {
+		ast_resolve_capabilities(&p->jointcaps,&p->jointcaps, chancaps, sipdebug_caps);
+	}
+	
+	if (chancaps->h264.rtpnum != 99)
+		p->jointcaps.h264.rtpnum = chancaps->h264.rtpnum;
+	
+	ast_copy_capabilities(&ast->channelcaps, &p->jointcaps);
+
+  if(sipdebug_caps)	{
+		if (p->jointcaps.maxcallbitrate) {
+			ast_verbose("SET_CAPABILITIES: New Jointcaps (%s)\n",ast->name);
+			ast_dump_caps(&p->jointcaps);
+		}
+	}
+	
+	return res;
+}
+
 /*! \brief  sip_fixup: Fix up a channel:  If a channel is consumed, this is called.
         Basically update any ->owner links */
 static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
@@ -3796,10 +3930,26 @@
 		break;
 	case AST_CONTROL_VIDUPDATE:	/* Request a video frame update */
 		if (p->vrtp && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
-			transmit_info_with_vidupdate(p);
-			/* ast_rtcp_send_h261fur(p->vrtp); */
+			/* Can possibly send both! */
+			if ((p->videoupdate & VIDEO_UPDATE_XML) == VIDEO_UPDATE_XML) 
+			  transmit_info_with_vidupdate(p);
+			if ((p->videoupdate & VIDEO_UPDATE_RTCP) == VIDEO_UPDATE_RTCP) 
+			  ast_rtcp_send_h261fur(p->vrtp);
+			if (p->videoupdate && sipdebug)
+			  ast_verbose("Sending %s FUR to %s\n", (p->videoupdate == 0) ? "none" : (p->videoupdate == VIDEO_UPDATE_XML) ? "XML" : (p->videoupdate == VIDEO_UPDATE_RTCP) ? "RTCP": "XML and RTCP", p->cid_num);  
 		} else
 			res = -1;
+		break;
+	case AST_CONTROL_CAPABILITY:
+		if (datalen == sizeof(struct ast_capabilities)) {
+			ast_resolve_capabilities(&p->jointcaps, &p->jointcaps, (struct ast_capabilities*)data, sipdebug_caps);
+			p->jointcapability = p->jointcapability | (AST_FORMAT_VIDEO_MASK & ast_get_int_from_capabilities(&p->jointcaps));
+			if(sipdebug_caps) {
+				ast_verbose("SIP INDICATE: We got a new cap of (0x%08x):\n",p->jointcapability);
+				ast_dump_caps(&p->jointcaps);
+			}
+		}
+		res = -1;
 		break;
 	case -1:
 		res = -1;
@@ -3826,7 +3976,11 @@
 	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 */
 	
@@ -3852,16 +4006,40 @@
 
 	/* 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);
-	if (option_debug > 2) {
+	tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | video | text;
+
+	if (!ast_are_caps_zero(&i->jointcaps)) {
+		if (sipdebug_caps) ast_verbose("SIP NEW: Chancaps(%s) = jointcaps\n",title ? title : i->fromdomain);
+		ast_copy_capabilities(&tmp->channelcaps, &i->jointcaps);
+	}	else if (!ast_are_caps_zero(&i->caps)) {
+		if (sipdebug_caps) ast_verbose("SIP NEW: Chancaps(%s) = conf caps\n",title ? title : i->fromdomain);
+		ast_copy_capabilities(&tmp->channelcaps, &i->caps);
+	} else {
+		if (sipdebug_caps) ast_verbose("SIP NEW: Chancaps(%s) = global caps\n",title ? title : i->fromdomain);
+		ast_copy_capabilities(&tmp->channelcaps, &global_caps);
+	}
+		
+  if(sipdebug_caps) {	
+		ast_verbose("SIP NEW: Chancaps(%s) are now\n", title ? title : i->fromdomain);
+		ast_dump_caps(&tmp->channelcaps);
+	}
+
+	if (sipdebug) {
 		char buf[BUFSIZ];
 		ast_log(LOG_DEBUG, "*** Our native formats are %s \n", ast_getformatname_multiple(buf, BUFSIZ, tmp->nativeformats));
 		ast_log(LOG_DEBUG, "*** Joint capabilities are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->jointcapability));
@@ -3884,14 +4062,26 @@
  		else
 			needvideo = i->jointcapability & AST_FORMAT_VIDEO_MASK;	/* Inbound call */
 	}
-
-	if (option_debug > 2) {
+	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 (sipdebug_caps) {
 		if (needvideo) 
 			ast_log(LOG_DEBUG, "This channel can handle video! HOLLYWOOD next!\n");
 		else
 			ast_log(LOG_DEBUG, "This channel will not be able to handle video.\n");
 	}
 
+	if (sipdebug_caps) {
+		if (needtext) 
+			ast_log(LOG_DEBUG, "This channel can handle text! Shakespeare next!\n");
+		else
+			ast_log(LOG_DEBUG, "This channel will not be able to handle text.\n");
+	}
 
 
 	if (ast_test_flag(&i->flags[0], SIP_DTMF) ==  SIP_DTMF_INBAND) {
@@ -3907,6 +4097,9 @@
 	if (needvideo && i->vrtp) {
 		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);
@@ -4123,6 +4316,19 @@
 	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;
@@ -4140,7 +4346,7 @@
 			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);
 			}
@@ -4284,11 +4490,15 @@
 		/* 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))

[... 2390 lines stripped ...]


More information about the asterisk-commits mailing list