[svn-commits] file: branch file/rtp_engine-mark2 r185013 - in /team/file/rtp_engine-mark2: ...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Mar 30 10:31:13 CDT 2009


Author: file
Date: Mon Mar 30 10:31:05 2009
New Revision: 185013

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=185013
Log:
Merged revisions 184948,184986 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

................
  r184948 | file | 2009-03-30 11:37:47 -0300 (Mon, 30 Mar 2009) | 21 lines
  
  Merged revisions 184947 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r184947 | file | 2009-03-30 11:35:47 -0300 (Mon, 30 Mar 2009) | 14 lines
    
    Improve our handling of T38 in the initial INVITE from a device.
    
    We now answer with matching media streams to what is requested. If an INVITE
    is received with both a T38 and RTP media stream this means we answer with both.
    For any outgoing calls created as a result of this inbound one no T38 is requested
    in the initial INVITE. Instead if we start receiving udptl packets we trigger a
    reinvite on the outbound side.
    
    (closes issue #12437)
    Reported by: marsosa
    Tested by: pinga-fogo, okrief, file, afu
    
    Review: http://reviewboard.digium.com/r/208/
  ........
................
  r184986 | mmichelson | 2009-03-30 12:25:04 -0300 (Mon, 30 Mar 2009) | 27 lines
  
  Blocked revisions 184980 via svnmerge
  
  ........
    r184980 | mmichelson | 2009-03-30 10:23:59 -0500 (Mon, 30 Mar 2009) | 22 lines
    
    Backport state interface changes to app_queue from trunk.
    
    After several issues raised on the Asterisk bugtracker against
    the 1.4 branch were determined to be fixable with the state interface
    change available in the 1.6.X series, it finally came time to just
    suck it up and backport the change.
    
    For a detailed explanation of what this change entails, the original
    trunk commit for this feature may be found here:
    
    http://svn.digium.com/view/asterisk?view=revision&revision=97203
    
    In addition, the details for the use of this change to fix the problems
    stated in issue #12970 may be found in the review request I made for
    this change. It is linked below.
    
    (closes issue #12970)
    Reported by: edugs15
    
    Review: http://reviewboard.digium.com/r/116
  ........
................

Modified:
    team/file/rtp_engine-mark2/   (props changed)
    team/file/rtp_engine-mark2/channels/chan_sip.c

Propchange: team/file/rtp_engine-mark2/
------------------------------------------------------------------------------
Binary property 'branch-1.4-blocked' - no diff available.

Propchange: team/file/rtp_engine-mark2/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Propchange: team/file/rtp_engine-mark2/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Mar 30 10:31:05 2009
@@ -1,1 +1,1 @@
-/trunk:1-184923
+/trunk:1-185001

Modified: team/file/rtp_engine-mark2/channels/chan_sip.c
URL: http://svn.digium.com/svn-view/asterisk/team/file/rtp_engine-mark2/channels/chan_sip.c?view=diff&rev=185013&r1=185012&r2=185013
==============================================================================
--- team/file/rtp_engine-mark2/channels/chan_sip.c (original)
+++ team/file/rtp_engine-mark2/channels/chan_sip.c Mon Mar 30 10:31:05 2009
@@ -1460,7 +1460,6 @@
 /*! \brief T38 States for a call */
 enum t38state {
 	T38_DISABLED = 0,                /*!< Not enabled */
-	T38_LOCAL_DIRECT,                /*!< Offered from local */
 	T38_LOCAL_REINVITE,              /*!< Offered from local - REINVITE */
 	T38_PEER_DIRECT,                 /*!< Offered from peer */
 	T38_PEER_REINVITE,               /*!< Offered from peer - REINVITE */
@@ -1474,6 +1473,7 @@
 	int peercapability;		/*!< Peers T38 capability */
 	int jointcapability;		/*!< Supported T38 capability at both ends */
 	enum t38state state;		/*!< T.38 state */
+	unsigned int direct:1;          /*!< Whether the T38 came from the initial invite or not */
 };
 
 /*! \brief Parameters to know status of transfer */
@@ -2300,7 +2300,7 @@
 static void add_noncodec_to_sdp(const struct sip_pvt *p, int format,
 				struct ast_str **m_buf, struct ast_str **a_buf,
 				int debug);
-static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp);
+static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38);
 static void do_setnat(struct sip_pvt *p, int natflags);
 static void stop_media_flows(struct sip_pvt *p);
 
@@ -3887,7 +3887,6 @@
 		/* Now if T38 support is enabled we need to look and see what the current state is to get what we want to report back */
 		if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT)) {
 			switch (p->t38.state) {
-			case T38_LOCAL_DIRECT:
 			case T38_LOCAL_REINVITE:
 			case T38_PEER_DIRECT:
 			case T38_PEER_REINVITE:
@@ -4609,6 +4608,10 @@
 	if (old == state)
 		return;
 
+	if (state == T38_PEER_DIRECT) {
+		p->t38.direct = 1;
+	}
+
 	p->t38.state = state;
 	ast_debug(2, "T38 state changed to %d on channel %s\n", p->t38.state, chan ? chan->name : "<none>");
 
@@ -5028,9 +5031,6 @@
 		} else if (!strcasecmp(ast_var_name(current), "SIPTRANSFER_REPLACES")) {
 			/* We're replacing a call. */
 			p->options->replaces = ast_var_value(current);
-		} else if (!strcasecmp(ast_var_name(current), "T38CALL")) {
-			p->t38.state = T38_LOCAL_DIRECT;
-			ast_debug(1, "T38State change to %d on channel %s\n", p->t38.state, ast->name);
 		}
 	}
 
@@ -5808,13 +5808,10 @@
 		ast_debug(1, "SIP answering channel: %s\n", ast->name);
 		if (p->t38.state == T38_PEER_DIRECT) {
 			change_t38_state(p, T38_ENABLED);
-			res = transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
-			ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
-		} else {
-			ast_rtp_instance_new_source(p->rtp);
-			res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE);
-			ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
-		}
+		}
+		ast_rtp_instance_new_source(p->rtp);
+		res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE);
+		ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
 	}
 	sip_pvt_unlock(p);
 	return res;
@@ -5851,9 +5848,13 @@
 					p->invitestate = INV_EARLY_MEDIA;
 					transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
 					ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);	
+				} else if (p->t38.state == T38_ENABLED && !p->t38.direct) {
+					change_t38_state(p, T38_DISABLED);
+					transmit_reinvite_with_sdp(p, FALSE, FALSE);
+				} else {
+					p->lastrtptx = time(NULL);
+					res = ast_rtp_instance_write(p->rtp, frame);
 				}
-				p->lastrtptx = time(NULL);
-				res = ast_rtp_instance_write(p->rtp, frame);
 			}
 			sip_pvt_unlock(p);
 		}
@@ -5908,8 +5909,16 @@
 				we simply forget the frames if we get modem frames before the bridge is up.
 				Fax will re-transmit.
 			*/
-			if (p->udptl && ast->_state == AST_STATE_UP) 
-				res = ast_udptl_write(p->udptl, frame);
+			if (ast->_state == AST_STATE_UP) {
+				if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->t38.state == T38_DISABLED) {
+					if (!p->pendinginvite) {
+						change_t38_state(p, T38_LOCAL_REINVITE);
+						transmit_reinvite_with_sdp(p, TRUE, FALSE);
+					}
+				} else if (p->udptl && p->t38.state == T38_ENABLED) {
+					res = ast_udptl_write(p->udptl, frame);
+				}
+			}
 			sip_pvt_unlock(p);
 		}
 		break;
@@ -6344,10 +6353,6 @@
 		pbx_builtin_setvar_helper(tmp, "SIPCALLID", i->callid);
 	if (i->rtp)
 		ast_jb_configure(tmp, &global_jbconf);
-
-	/* If the INVITE contains T.38 SDP information set the proper channel variable so a created outgoing call will also have T.38 */
-	if (i->udptl && i->t38.state == T38_PEER_DIRECT)
-		pbx_builtin_setvar_helper(tmp, "_T38CALL", "1");
 
 	/* Set channel variables for this call from configuration */
 	for (v = i->chanvars ; v ; v = v->next) {
@@ -7998,7 +8003,7 @@
 
 		/* Remote party offers T38, we need to update state */
 		if (t38action == SDP_T38_ACCEPT) {
-			if (p->t38.state == T38_LOCAL_DIRECT || p->t38.state == T38_LOCAL_REINVITE)
+			if (p->t38.state == T38_LOCAL_REINVITE)
 				change_t38_state(p, T38_ENABLED);
 		} else if (t38action == SDP_T38_INITIATE) {
 			if (p->owner && p->lastinvite) {
@@ -9118,92 +9123,6 @@
 	}
 }
 
-/*! \brief Add T.38 Session Description Protocol message */
-static int add_t38_sdp(struct sip_request *resp, struct sip_pvt *p)
-{
-	int len = 0;
-	int x = 0;
-	struct sockaddr_in udptlsin;
-	struct ast_str *m_modem = ast_str_alloca(1024);
-	struct ast_str *a_modem = ast_str_alloca(1024);
-	struct sockaddr_in udptldest = { 0, };
-	int debug;
-	
-	debug = sip_debug_test_pvt(p);
-	len = 0;
-	if (!p->udptl) {
-		ast_log(LOG_WARNING, "No way to add SDP without an UDPTL structure\n");
-		return -1;
-	}
-	
-	if (!p->sessionid) {
-		p->sessionid = (int)ast_random();
-		p->sessionversion = p->sessionid;
-	} else
-		p->sessionversion++;
-	
-	/* Our T.38 end is */
-	ast_udptl_get_us(p->udptl, &udptlsin);
-	
-	/* Determine T.38 UDPTL destination */
-	if (p->udptlredirip.sin_addr.s_addr) {
-		udptldest.sin_port = p->udptlredirip.sin_port;
-		udptldest.sin_addr = p->udptlredirip.sin_addr;
-	} else {
-		udptldest.sin_addr = p->ourip.sin_addr;
-		udptldest.sin_port = udptlsin.sin_port;
-	}
-	
-	if (debug) 
-		ast_debug(1, "T.38 UDPTL is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(udptlsin.sin_port));
-	
-	/* We break with the "recommendation" and send our IP, in order that our
-	   peer doesn't have to ast_gethostbyname() us */
-	
-	if (debug) {
-		ast_debug(1, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
-			p->t38.capability,
-			p->t38.peercapability,
-			p->t38.jointcapability);
-	}
-	ast_str_append(&m_modem, 0, "v=0\r\n");
-	ast_str_append(&m_modem, 0, "o=%s %d %d IN IP4 %s\r\n", ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner , p->sessionid, p->sessionversion, ast_inet_ntoa(udptldest.sin_addr));
-	ast_str_append(&m_modem, 0, "s=%s\r\n", ast_strlen_zero(global_sdpsession) ? "-" : global_sdpsession);
-	ast_str_append(&m_modem, 0, "c=IN IP4 %s\r\n", ast_inet_ntoa(udptldest.sin_addr));
-	ast_str_append(&m_modem, 0, "t=0 0\r\n");
-	ast_str_append(&m_modem, 0, "m=image %d udptl t38\r\n", ntohs(udptldest.sin_port));
-	
-	if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_0)
-		ast_str_append(&a_modem, 0, "a=T38FaxVersion:0\r\n");
-	if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_1)
-		ast_str_append(&a_modem, 0, "a=T38FaxVersion:1\r\n");
-	if ((x = t38_get_rate(p->t38.jointcapability)))
-		ast_str_append(&a_modem, 0, "a=T38MaxBitRate:%d\r\n", x);
-	if ((p->t38.jointcapability & T38FAX_FILL_BIT_REMOVAL) == T38FAX_FILL_BIT_REMOVAL)
-		ast_str_append(&a_modem, 0, "a=T38FaxFillBitRemoval\r\n");
-	if ((p->t38.jointcapability & T38FAX_TRANSCODING_MMR) == T38FAX_TRANSCODING_MMR)
-		ast_str_append(&a_modem, 0, "a=T38FaxTranscodingMMR\r\n");
-	if ((p->t38.jointcapability & T38FAX_TRANSCODING_JBIG) == T38FAX_TRANSCODING_JBIG)
-		ast_str_append(&a_modem, 0, "a=T38FaxTranscodingJBIG\r\n");
-	ast_str_append(&a_modem, 0, "a=T38FaxRateManagement:%s\r\n", (p->t38.jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) ? "localTCF" : "transferredTCF");
-	x = ast_udptl_get_local_max_datagram(p->udptl);
-	ast_str_append(&a_modem, 0, "a=T38FaxMaxBuffer:%d\r\n", x);
-	ast_str_append(&a_modem, 0, "a=T38FaxMaxDatagram:%d\r\n", x);
-	if (p->t38.jointcapability != T38FAX_UDP_EC_NONE)
-		ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:%s\r\n", (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY) ? "t38UDPRedundancy" : "t38UDPFEC");
-	len = m_modem->used + a_modem->used;
-	add_header(resp, "Content-Type", "application/sdp");
-	add_header_contentLength(resp, len);
-	add_line(resp, m_modem->str);
-	add_line(resp, a_modem->str);
-
-	/* Update lastrtprx when we send our SDP */
-	p->lastrtprx = p->lastrtptx = time(NULL);
-	
-	return 0;
-}
-
-
 /*! \brief Add RFC 2833 DTMF offer to SDP */
 static void add_noncodec_to_sdp(const struct sip_pvt *p, int format,
 				struct ast_str **m_buf, struct ast_str **a_buf,
@@ -9266,7 +9185,7 @@
     is used in Session-Timers where RE-INVITEs are used for refreshing SIP sessions 
     without modifying the media session in any way. 
 */
-static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp)
+static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38)
 {
 	int len = 0;
 	int alreadysent = 0;
@@ -9275,8 +9194,10 @@
 	struct sockaddr_in vsin;
 	struct sockaddr_in tsin;
 	struct sockaddr_in dest;
+	struct sockaddr_in udptlsin;
 	struct sockaddr_in vdest = { 0, };
 	struct sockaddr_in tdest = { 0, };
+	struct sockaddr_in udptldest = { 0, };
 
 	/* SDP fields */
 	char *version = 	"v=0\r\n";		/* Protocol version */
@@ -9285,16 +9206,18 @@
 	char connection[256];				/* Connection data */
 	char *session_time = "t=0 0\r\n"; 			/* Time the session is active */
 	char bandwidth[256] = "";			/* Max bitrate */
-	char *hold;
+	char *hold = "";
 	struct ast_str *m_audio = ast_str_alloca(256);  /* Media declaration line for audio */
 	struct ast_str *m_video = ast_str_alloca(256);  /* Media declaration line for video */
 	struct ast_str *m_text = ast_str_alloca(256);   /* Media declaration line for text */
+	struct ast_str *m_modem = ast_str_alloca(256);  /* Media declaration line for modem */
 	struct ast_str *a_audio = ast_str_alloca(1024); /* Attributes for audio */
 	struct ast_str *a_video = ast_str_alloca(1024); /* Attributes for video */
 	struct ast_str *a_text = ast_str_alloca(1024);  /* Attributes for text */
+	struct ast_str *a_modem = ast_str_alloca(1024); /* Attributes for modem */
 
 	int x;
-	int capability;
+	int capability = 0;
 	int needaudio = FALSE;
 	int needvideo = FALSE;
 	int needtext = FALSE;
@@ -9325,177 +9248,226 @@
 			p->sessionversion++;
 	}
 
-	capability = p->jointcapability;
-
-	/* XXX note, Video and Text are negated - 'true' means 'no' */
- 	ast_debug(1, "** Our capability: %s Video flag: %s Text flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability), 
- 		p->novideo ? "True" : "False", p->notext ? "True" : "False");
-	ast_debug(1, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec));
+	get_our_media_address(p, needvideo, &sin, &vsin, &tsin, &dest, &vdest);
+
+	snprintf(owner, sizeof(owner), "o=%s %d %d IN IP4 %s\r\n", ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner, p->sessionid, p->sessionversion, ast_inet_ntoa(dest.sin_addr));
+	snprintf(connection, sizeof(connection), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
+
+	if (add_audio) {
+		capability = p->jointcapability;
+
+		/* XXX note, Video and Text are negated - 'true' means 'no' */
+		ast_debug(1, "** Our capability: %s Video flag: %s Text flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability), 
+			  p->novideo ? "True" : "False", p->notext ? "True" : "False");
+		ast_debug(1, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec));
 	
 #ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
-	if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_RTP)) {
-		ast_str_append(&m_audio, 0, " %d", 191);
-		ast_str_append(&a_audio, 0, "a=rtpmap:%d %s/%d\r\n", 191, "t38", 8000);
-	}
+		if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_RTP)) {
+			ast_str_append(&m_audio, 0, " %d", 191);
+			ast_str_append(&a_audio, 0, "a=rtpmap:%d %s/%d\r\n", 191, "t38", 8000);
+		}
 #endif
 
-	/* Check if we need audio */
-	if (capability & AST_FORMAT_AUDIO_MASK)
-		needaudio = TRUE;
-
-	/* Check if we need video in this call */
-	if ((capability & AST_FORMAT_VIDEO_MASK) && !p->novideo) {
-		if (p->vrtp) {
-			needvideo = TRUE;
-			ast_debug(2, "This call needs video offers!\n");
-		} else
-			ast_debug(2, "This call needs video offers, but there's no video support enabled!\n");
-	}
-
-	/* Get our media addresses */
-	get_our_media_address(p, needvideo, &sin, &vsin, &tsin, &dest, &vdest);
+		/* Check if we need audio */
+		if (capability & AST_FORMAT_AUDIO_MASK)
+			needaudio = TRUE;
+
+		/* Check if we need video in this call */
+		if ((capability & AST_FORMAT_VIDEO_MASK) && !p->novideo) {
+			if (p->vrtp) {
+				needvideo = TRUE;
+				ast_debug(2, "This call needs video offers!\n");
+			} else
+				ast_debug(2, "This call needs video offers, but there's no video support enabled!\n");
+		}
+
+		if (debug) 
+			ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), 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) {
+			ast_str_append(&m_video, 0, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
+
+			/* Build max bitrate string */
+			if (p->maxcallbitrate)
+				snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->maxcallbitrate);
+			if (debug) 
+				ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(vsin.sin_port));	
+		}
+
+		/* Check if we need text in this call */
+		if((capability & AST_FORMAT_TEXT_MASK) && !p->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;
+				ast_debug(2, "This call needs text offers! \n");
+			} else
+				ast_debug(2, "This call needs text offers, but there's no text support enabled ! \n");
+		}
 		
-	if (debug) 
-		ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), 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) {
-		ast_str_append(&m_video, 0, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
-
-		/* Build max bitrate string */
-		if (p->maxcallbitrate)
-			snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->maxcallbitrate);
-		if (debug) 
-			ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(vsin.sin_port));	
-	}
-
-	/* Check if we need text in this call */
-	if((capability & AST_FORMAT_TEXT_MASK) && !p->notext) {
-		if (sipdebug_text)
-			ast_verbose("We think we can do text\n");
-		if (p->trtp) {
+		/* 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("And we have a text rtp object\n");
-			needtext = TRUE;
-			ast_debug(2, "This call needs text offers! \n");
-		} else
-			ast_debug(2, "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;
+				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.sin_addr;
+				tdest.sin_port = tsin.sin_port;
+			}
+			ast_str_append(&m_text, 0, "m=text %d RTP/AVP", ntohs(tdest.sin_port));
+			if (debug) /* XXX should I use tdest below ? */
+				ast_verbose("Text is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(tsin.sin_port));	
+
+		}
+
+		/* Start building generic SDP headers */
+
+		/* We break with the "recommendation" and send our IP, in order that our
+		   peer doesn't have to ast_gethostbyname() us */
+
+		ast_str_append(&m_audio, 0, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
+
+		if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR)
+			hold = "a=recvonly\r\n";
+		else if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_INACTIVE)
+			hold = "a=inactive\r\n";
+		else
+			hold = "a=sendrecv\r\n";
+
+		/* Now, start adding audio codecs. These are added in this order:
+		   - First what was requested by the calling channel
+		   - Then preferences in order from sip.conf device config for this peer/user
+		   - Then other codecs in capabilities, including video
+		*/
+
+		/* Prefer the audio codec we were requested to use, first, no matter what 
+		   Note that p->prefcodec can include video codecs, so mask them out
+		*/
+		if (capability & p->prefcodec) {
+			int codec = p->prefcodec & AST_FORMAT_AUDIO_MASK;
+
+			add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size);
+			alreadysent |= codec;
+		}
+
+		/* Start by sending our preferred audio/video codecs */
+		for (x = 0; x < 32; x++) {
+			int codec;
+
+			if (!(codec = ast_codec_pref_index(&p->prefs, x)))
+				break; 
+
+			if (!(capability & codec))
+				continue;
+
+			if (alreadysent & codec)
+				continue;
+
+			add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size);
+			alreadysent |= codec;
+		}
+
+		/* Now send any other common audio and video codecs, and non-codec formats: */
+		for (x = 1; x <= (needtext ? AST_FORMAT_TEXT_MASK : (needvideo ? AST_FORMAT_VIDEO_MASK : AST_FORMAT_AUDIO_MASK)); x <<= 1) {
+			if (!(capability & x))	/* Codec not requested */
+				continue;
+
+			if (alreadysent & x)	/* Already added to SDP */
+				continue;
+
+			if (x & AST_FORMAT_AUDIO_MASK)
+				add_codec_to_sdp(p, x, &m_audio, &a_audio, debug, &min_audio_packet_size);
+			else if (x & AST_FORMAT_VIDEO_MASK)
+				add_vcodec_to_sdp(p, x, &m_video, &a_video, debug, &min_video_packet_size);
+			else if (x & AST_FORMAT_TEXT_MASK)
+				add_tcodec_to_sdp(p, x, &m_text, &a_text, debug, &min_text_packet_size);
+		}
+
+		/* Now add DTMF RFC2833 telephony-event as a codec */
+		for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
+			if (!(p->jointnoncodeccapability & x))
+				continue;
+
+			add_noncodec_to_sdp(p, x, &m_audio, &a_audio, debug);
+		}
+
+		ast_debug(3, "-- Done with adding codecs to SDP\n");
+
+		if (!p->owner || !ast_internal_timing_enabled(p->owner))
+			ast_str_append(&a_audio, 0, "a=silenceSupp:off - - - -\r\n");
+
+		if (min_audio_packet_size)
+			ast_str_append(&a_audio, 0, "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_str_append(&a_video, 0, "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_str_append(&a_text, 0, "a=ptime:%d\r\n", min_text_packet_size);
+ 
+		if (m_audio->len - m_audio->used < 2 || m_video->len - m_video->used < 2 ||
+		    m_text->len - m_text->used < 2 || a_text->len - a_text->used < 2 ||
+		    a_audio->len - a_audio->used < 2 || a_video->len - a_video->used < 2)
+			ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
+	}
+
+	if (add_t38) {
+		/* Our T.38 end is */
+		ast_udptl_get_us(p->udptl, &udptlsin);
+
+		/* Determine T.38 UDPTL destination */
+		if (p->udptlredirip.sin_addr.s_addr) {
+			udptldest.sin_port = p->udptlredirip.sin_port;
+			udptldest.sin_addr = p->udptlredirip.sin_addr;
 		} else {
-			tdest.sin_addr = p->ourip.sin_addr;
-			tdest.sin_port = tsin.sin_port;
-		}
-		ast_str_append(&m_text, 0, "m=text %d RTP/AVP", ntohs(tdest.sin_port));
-
-		if (debug) /* XXX should I use tdest below ? */
-			ast_verbose("Text is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(tsin.sin_port));	
-
-	}
-
-	/* Start building generic SDP headers */
-
-	/* We break with the "recommendation" and send our IP, in order that our
-	   peer doesn't have to ast_gethostbyname() us */
-
-	snprintf(owner, sizeof(owner), "o=%s %d %d IN IP4 %s\r\n", ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner, p->sessionid, p->sessionversion, ast_inet_ntoa(dest.sin_addr));
-	snprintf(connection, sizeof(connection), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
-	ast_str_append(&m_audio, 0, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
-
-	if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR)
-		hold = "a=recvonly\r\n";
-	else if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_INACTIVE)
-		hold = "a=inactive\r\n";
-	else
-		hold = "a=sendrecv\r\n";
-
-	/* Now, start adding audio codecs. These are added in this order:
-		- First what was requested by the calling channel
-		- Then preferences in order from sip.conf device config for this peer/user
-		- Then other codecs in capabilities, including video
-	*/
-
-	/* Prefer the audio codec we were requested to use, first, no matter what 
-		Note that p->prefcodec can include video codecs, so mask them out
-	 */
-	if (capability & p->prefcodec) {
-		int codec = p->prefcodec & AST_FORMAT_AUDIO_MASK;
-
-		add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size);
-		alreadysent |= codec;
-	}
-
-	/* Start by sending our preferred audio/video codecs */
-	for (x = 0; x < 32; x++) {
-		int codec;
-
-		if (!(codec = ast_codec_pref_index(&p->prefs, x)))
-			break; 
-
-		if (!(capability & codec))
-			continue;
-
-		if (alreadysent & codec)
-			continue;
-
-		add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size);
-		alreadysent |= codec;
-	}
-
-	/* Now send any other common audio and video codecs, and non-codec formats: */
-	for (x = 1; x <= (needtext ? AST_FORMAT_TEXT_MASK : (needvideo ? AST_FORMAT_VIDEO_MASK : AST_FORMAT_AUDIO_MASK)); x <<= 1) {
-		if (!(capability & x))	/* Codec not requested */
-			continue;
-
-		if (alreadysent & x)	/* Already added to SDP */
-			continue;
-
-		if (x & AST_FORMAT_AUDIO_MASK)
-			add_codec_to_sdp(p, x, &m_audio, &a_audio, debug, &min_audio_packet_size);
-		else if (x & AST_FORMAT_VIDEO_MASK)
-			add_vcodec_to_sdp(p, x, &m_video, &a_video, debug, &min_video_packet_size);
-		else if (x & AST_FORMAT_TEXT_MASK)
-			add_tcodec_to_sdp(p, x, &m_text, &a_text, debug, &min_text_packet_size);
-	}
-
-	/* Now add DTMF RFC2833 telephony-event as a codec */
-	for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
-		if (!(p->jointnoncodeccapability & x))
-			continue;
-
-		add_noncodec_to_sdp(p, x, &m_audio, &a_audio, debug);
-	}
-
-	ast_debug(3, "-- Done with adding codecs to SDP\n");
-
-	if (!p->owner || !ast_internal_timing_enabled(p->owner))
-		ast_str_append(&a_audio, 0, "a=silenceSupp:off - - - -\r\n");
-
-	if (min_audio_packet_size)
-		ast_str_append(&a_audio, 0, "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_str_append(&a_video, 0, "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_str_append(&a_text, 0, "a=ptime:%d\r\n", min_text_packet_size);
- 
-	if (m_audio->len - m_audio->used < 2 || m_video->len - m_video->used < 2 ||
-			m_text->len - m_text->used < 2 || a_text->len - a_text->used < 2 ||
-			a_audio->len - a_audio->used < 2 || a_video->len - a_video->used < 2)
-		ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
+			udptldest.sin_addr = p->ourip.sin_addr;
+			udptldest.sin_port = udptlsin.sin_port;
+		}
+
+		if (debug)
+			ast_debug(1, "T.38 UDPTL is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(udptlsin.sin_port));
+
+		/* We break with the "recommendation" and send our IP, in order that our
+		   peer doesn't have to ast_gethostbyname() us */
+
+		if (debug) {
+			ast_debug(1, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
+				  p->t38.capability,
+				  p->t38.peercapability,
+				  p->t38.jointcapability);
+		}
+
+		ast_str_append(&m_modem, 0, "m=image %d udptl t38", ntohs(udptldest.sin_port));
+
+		if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_0)
+			ast_str_append(&a_modem, 0, "a=T38FaxVersion:0\r\n");
+		if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_1)
+			ast_str_append(&a_modem, 0, "a=T38FaxVersion:1\r\n");
+		if ((x = t38_get_rate(p->t38.jointcapability)))
+			ast_str_append(&a_modem, 0, "a=T38MaxBitRate:%d\r\n", x);
+		if ((p->t38.jointcapability & T38FAX_FILL_BIT_REMOVAL) == T38FAX_FILL_BIT_REMOVAL)
+			ast_str_append(&a_modem, 0, "a=T38FaxFillBitRemoval\r\n");
+		if ((p->t38.jointcapability & T38FAX_TRANSCODING_MMR) == T38FAX_TRANSCODING_MMR)
+			ast_str_append(&a_modem, 0, "a=T38FaxTranscodingMMR\r\n");
+		if ((p->t38.jointcapability & T38FAX_TRANSCODING_JBIG) == T38FAX_TRANSCODING_JBIG)
+			ast_str_append(&a_modem, 0, "a=T38FaxTranscodingJBIG\r\n");
+		ast_str_append(&a_modem, 0, "a=T38FaxRateManagement:%s\r\n", (p->t38.jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) ? "localTCF" : "transferredTCF");
+		x = ast_udptl_get_local_max_datagram(p->udptl);
+		ast_str_append(&a_modem, 0, "a=T38FaxMaxBuffer:%d\r\n", x);
+		ast_str_append(&a_modem, 0, "a=T38FaxMaxDatagram:%d\r\n", x);
+		if (p->t38.jointcapability != T38FAX_UDP_EC_NONE)
+			ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:%s\r\n", (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY) ? "t38UDPRedundancy" : "t38UDPFEC");
+	}
 
 	if (needaudio)
  		ast_str_append(&m_audio, 0, "\r\n");
@@ -9503,6 +9475,8 @@
  		ast_str_append(&m_video, 0, "\r\n");
  	if (needtext)
  		ast_str_append(&m_text, 0, "\r\n");
+	if (add_t38)
+		ast_str_append(&m_modem, 0, "\r\n");
 
  	len = strlen(version) + strlen(subject) + strlen(owner) +
 		strlen(connection) + strlen(session_time);
@@ -9512,6 +9486,8 @@
  		len += m_video->used + a_video->used + strlen(bandwidth) + strlen(hold);
  	if (needtext) /* only if text response is appropriate */
  		len += m_text->used + a_text->used + strlen(hold);
+	if (add_t38)
+		len += m_modem->used + a_modem->used;
 
 	add_header(resp, "Content-Type", "application/sdp");
 	add_header_contentLength(resp, len);
@@ -9537,6 +9513,10 @@
 		add_line(resp, a_text->str);
 		add_line(resp, hold);	/* Repeat hold for the text stream */
 	}
+	if (add_t38) {
+		add_line(resp, m_modem->str);
+		add_line(resp, a_modem->str);
+	}
 
 	/* Update lastrtprx when we send our SDP */
 	p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
@@ -9559,7 +9539,7 @@
 	respprep(&resp, p, msg, req);
 	if (p->udptl) {
 		ast_udptl_offered_from_local(p->udptl, 0);
-		add_t38_sdp(&resp, p);
+		add_sdp(&resp, p, 0, 0, 1);
 	} else 
 		ast_log(LOG_ERROR, "Can't add SDP to response, since we have no UDPTL session allocated. Call-ID %s\n", p->callid);
 	if (retrans && !p->pendinginvite)
@@ -9608,8 +9588,12 @@
 			ast_debug(1, "Setting framing from config on incoming call\n");
 			ast_rtp_codecs_packetization_set(&p->rtp->codecs, p->rtp, &p->prefs);
 		}
-		try_suggested_sip_codec(p);	
-		add_sdp(&resp, p, oldsdp);
+		try_suggested_sip_codec(p);
+		if (p->t38.state == T38_PEER_DIRECT || p->t38.state == T38_ENABLED) {
+			add_sdp(&resp, p, oldsdp, TRUE, TRUE);
+		} else {
+			add_sdp(&resp, p, oldsdp, TRUE, FALSE);
+		}
 	} else 
 		ast_log(LOG_ERROR, "Can't add SDP to response, since we have no RTP session allocated. Call-ID %s\n", p->callid);
 	if (reliable && !p->pendinginvite)
@@ -9691,9 +9675,9 @@
 	if (p->do_history)
 		append_history(p, "ReInv", "Re-invite sent");
 	if (t38version)
-		add_t38_sdp(&req, p);
+		add_sdp(&req, p, oldsdp, FALSE, TRUE);
 	else
-		add_sdp(&req, p, oldsdp);
+		add_sdp(&req, p, oldsdp, TRUE, FALSE);
 
 	/* Use this as the basis */
 	initialize_initreq(p, &req);
@@ -10096,12 +10080,12 @@
 		ast_channel_unlock(chan);
 	}
 	if (sdp) {
-		if (p->udptl && (p->t38.state == T38_LOCAL_DIRECT || p->t38.state == T38_LOCAL_REINVITE)) {
+		if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
 			ast_udptl_offered_from_local(p->udptl, 1);
 			ast_debug(1, "T38 is in state %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
-			add_t38_sdp(&req, p);
+			add_sdp(&req, p, FALSE, FALSE, TRUE);
 		} else if (p->rtp) 
-			add_sdp(&req, p, FALSE);
+			add_sdp(&req, p, FALSE, TRUE, FALSE);
 	} else {
 		if (!p->notify_headers) {
 			add_header_contentLength(&req, 0);
@@ -16798,20 +16782,6 @@
 
 			/* Trigger a reinvite back to audio */
 			transmit_reinvite_with_sdp(p, FALSE, FALSE);
-		} else if (p->udptl && p->t38.state == T38_LOCAL_DIRECT) {
-			/* We tried to send T.38 out in an initial INVITE and the remote side rejected it,
-			   right now we can't fall back to audio so totally abort.
-			*/
-			/* Try to reset RTP timers */
-			//ast_rtp_set_rtptimers_onhold(p->rtp);
-			ast_log(LOG_ERROR, "Got error on T.38 initial invite. Bailing out.\n");
-
-			change_t38_state(p, T38_DISABLED);
-			/* The dialog is now terminated */
-			if (p->owner && !req->ignore)
-				ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
-			pvt_set_needdestroy(p, "got error on T.38 initial invite");
-			sip_alreadygone(p);
 		} else {
 			/* We can't set up this call, so give up */
 			if (p->owner && !req->ignore)




More information about the svn-commits mailing list