[svn-commits] file: branch 1.6.1 r203703 - in /branches/1.6.1: ./ apps/ channels/ configs/ ...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Jun 26 14:31:40 CDT 2009


Author: file
Date: Fri Jun 26 14:31:36 2009
New Revision: 203703

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=203703
Log:
Merged revisions 203699 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

........
  r203699 | file | 2009-06-26 16:27:24 -0300 (Fri, 26 Jun 2009) | 2 lines
  
  Improve T.38 negotiation by exchanging session parameters between application and channel.
........

Modified:
    branches/1.6.1/   (props changed)
    branches/1.6.1/apps/app_fax.c
    branches/1.6.1/channels/chan_sip.c
    branches/1.6.1/configs/sip.conf.sample
    branches/1.6.1/include/asterisk/frame.h
    branches/1.6.1/main/channel.c
    branches/1.6.1/main/frame.c
    branches/1.6.1/main/rtp.c

Propchange: branches/1.6.1/
------------------------------------------------------------------------------
Binary property 'trunk-merged' - no diff available.

Modified: branches/1.6.1/apps/app_fax.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.1/apps/app_fax.c?view=diff&rev=203703&r1=203702&r2=203703
==============================================================================
--- branches/1.6.1/apps/app_fax.c (original)
+++ branches/1.6.1/apps/app_fax.c Fri Jun 26 14:31:36 2009
@@ -116,7 +116,7 @@
 	int direction;			/* Fax direction: 0 - receiving, 1 - sending */
 	int caller_mode;
 	char *file_name;
-	
+	struct ast_control_t38_parameters t38parameters;
 	volatile int finished;
 } fax_session;
 
@@ -327,7 +327,6 @@
 	struct ast_frame *fr;
 	int last_state = 0;
 	struct timeval now, start, state_change;
-	enum ast_control_t38 t38control;
 
 #if SPANDSP_RELEASE_DATE >= 20080725
         /* for spandsp shaphots 0.0.6 and higher */
@@ -411,9 +410,16 @@
 			/* Do not pass channel to ast_dsp_process otherwise it may queue modified audio frame back */
 			fr = ast_dsp_process(NULL, dsp, fr);
 			if (fr && fr->frametype == AST_FRAME_DTMF && fr->subclass == 'f') {
+				struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_NEGOTIATE,
+										 .version = 0,
+										 .max_datagram = 400,
+										 .rate = AST_T38_RATE_9600,
+										 .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERED_TCF,
+										 .fill_bit_removal = 1,
+										 .transcoding_mmr = 1,
+				};
 				ast_debug(1, "Fax tone detected. Requesting T38\n");
-				t38control = AST_T38_REQUEST_NEGOTIATE;
-				ast_indicate_data(s->chan, AST_CONTROL_T38, &t38control, sizeof(t38control));
+				ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
 				detect_tone = 0;
 			}
 
@@ -438,11 +444,11 @@
 				state_change = ast_tvnow();
 				last_state = t30state->state;
 			}
-		} else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
-				inf->datalen == sizeof(enum ast_control_t38)) {
-			t38control =*((enum ast_control_t38 *) inf->data.ptr);
-			if (t38control == AST_T38_NEGOTIATED) {
+		} else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38_PARAMETERS) {
+			struct ast_control_t38_parameters *parameters = inf->data.ptr;
+			if (parameters->request_response == AST_T38_NEGOTIATED) {
 				/* T38 switchover completed */
+				s->t38parameters = *parameters;
 				ast_debug(1, "T38 negotiated, finishing audio loop\n");
 				res = 1;
 				break;
@@ -503,8 +509,6 @@
 	struct ast_frame *inf = NULL;
 	int last_state = 0;
 	struct timeval now, start, state_change, last_frame;
-	enum ast_control_t38 t38control;
-
 	t30_state_t *t30state;
 	t38_core_state_t *t38state;
 
@@ -525,6 +529,17 @@
 		return -1;
 	}
 
+	t38_set_max_datagram_size(t38state, s->t38parameters.max_datagram);
+
+	if (s->t38parameters.fill_bit_removal) {
+		t38_set_fill_bit_removal(t38state, TRUE);
+	}
+	if (s->t38parameters.transcoding_mmr) {
+		t38_set_mmr_transcoding(t38state, TRUE);
+	} else if (s->t38parameters.transcoding_jbig) {
+		t38_set_jbig_transcoding(t38state, TRUE);
+	}
+
 	/* Setup logging */
 	set_logging(&t38.logging);
 	set_logging(&t30state->logging);
@@ -568,12 +583,9 @@
 				state_change = ast_tvnow();
 				last_state = t30state->state;
 			}
-		} else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
-				inf->datalen == sizeof(enum ast_control_t38)) {
-
-			t38control = *((enum ast_control_t38 *) inf->data.ptr);
-
-			if (t38control == AST_T38_TERMINATED || t38control == AST_T38_REFUSED) {
+		} else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38_PARAMETERS) {
+			struct ast_control_t38_parameters *parameters = inf->data.ptr;
+			if (parameters->request_response == AST_T38_TERMINATED || parameters->request_response == AST_T38_REFUSED) {
 				ast_debug(1, "T38 down, terminating\n");
 				res = -1;
 				break;
@@ -664,7 +676,7 @@
 {
 	int res = 0;
 	char *parse;
-	fax_session session;
+	fax_session session = { 0, };
 
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(file_name);

Modified: branches/1.6.1/channels/chan_sip.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.1/channels/chan_sip.c?view=diff&rev=203703&r1=203702&r2=203703
==============================================================================
--- branches/1.6.1/channels/chan_sip.c (original)
+++ branches/1.6.1/channels/chan_sip.c Fri Jun 26 14:31:36 2009
@@ -1067,10 +1067,10 @@
 #define SIP_PAGE2_SUBSCRIBEMWIONLY	(1 << 18)	/*!< GP: Only issue MWI notification if subscribed to */
 #define SIP_PAGE2_IGNORESDPVERSION	(1 << 19)	/*!< GDP: Ignore the SDP session version number we receive and treat all sessions as new */
 
-#define SIP_PAGE2_T38SUPPORT		(7 << 20)	/*!< GDP: T38 Fax Passthrough Support */
-#define SIP_PAGE2_T38SUPPORT_UDPTL	(1 << 20)	/*!< GDP: T38 Fax Passthrough Support */
-#define SIP_PAGE2_T38SUPPORT_RTP	(2 << 20)	/*!< GDP: T38 Fax Passthrough Support (not implemented) */
-#define SIP_PAGE2_T38SUPPORT_TCP	(4 << 20)	/*!< GDP: T38 Fax Passthrough Support (not implemented) */
+#define SIP_PAGE2_T38SUPPORT		        (7 << 20)	/*!< GDP: T38 Fax Passthrough Support */
+#define SIP_PAGE2_T38SUPPORT_UDPTL	        (1 << 20)	/*!< GDP: T38 Fax Passthrough Support (no error correction) */
+#define SIP_PAGE2_T38SUPPORT_UDPTL_FEC	        (2 << 20)	/*!< GDP: T38 Fax Passthrough Support (FEC error correction) */
+#define SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY	(4 << 20)	/*!< GDP: T38 Fax Passthrough Support (redundancy error correction) */
 
 #define SIP_PAGE2_CALL_ONHOLD		(3 << 23)	/*!< D: Call hold states: */
 #define SIP_PAGE2_CALL_ONHOLD_ACTIVE    (1 << 23)       /*!< D: Active hold */
@@ -1146,7 +1146,6 @@
 enum t38state {
 	T38_DISABLED = 0,                /*!< Not enabled */
 	T38_LOCAL_REINVITE,              /*!< Offered from local - REINVITE */
-	T38_PEER_DIRECT,                 /*!< Offered from peer */
 	T38_PEER_REINVITE,               /*!< Offered from peer - REINVITE */
 	T38_ENABLED                      /*!< Negotiated (enabled) */
 };
@@ -1158,7 +1157,6 @@
 	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 */
@@ -3577,7 +3575,6 @@
 		if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT)) {
 			switch (p->t38.state) {
 			case T38_LOCAL_REINVITE:
-			case T38_PEER_DIRECT:
 			case T38_PEER_REINVITE:
 				state = T38_STATE_NEGOTIATING;
 				break;
@@ -4307,21 +4304,62 @@
 	}
 }
 
+/*! \brief Helper function which interprets T.38 capabilities and fills a parameters structure in */
+static void fill_t38_parameters(int capabilities, struct ast_control_t38_parameters *parameters, struct sip_pvt *p)
+{
+	if (capabilities & T38FAX_VERSION_0) {
+		parameters->version = 0;
+	} else if (capabilities & T38FAX_VERSION_1) {
+		parameters->version = 1;
+	}
+
+	if (capabilities & T38FAX_RATE_14400) {
+		parameters->rate = AST_T38_RATE_14400;
+	} else if (capabilities & T38FAX_RATE_12000) {
+		parameters->rate = AST_T38_RATE_12000;
+	} else if (capabilities & T38FAX_RATE_9600) {
+		parameters->rate = AST_T38_RATE_9600;
+	} else if (capabilities & T38FAX_RATE_7200) {
+		parameters->rate = AST_T38_RATE_7200;
+	} else if (capabilities & T38FAX_RATE_4800) {
+		parameters->rate = AST_T38_RATE_4800;
+	} else if (capabilities & T38FAX_RATE_2400) {
+		parameters->rate = AST_T38_RATE_2400;
+	}
+
+	if (capabilities & T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF) {
+		parameters->rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERED_TCF;
+	} else if (capabilities & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) {
+		parameters->rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
+	}
+
+	if (capabilities & T38FAX_FILL_BIT_REMOVAL) {
+		parameters->fill_bit_removal = 1;
+	}
+
+	if (capabilities & T38FAX_TRANSCODING_MMR) {
+		parameters->transcoding_mmr = 1;
+	}
+
+	if (capabilities & T38FAX_TRANSCODING_JBIG) {
+		parameters->transcoding_jbig = 1;
+	}
+
+	parameters->max_datagram = ast_udptl_get_far_max_datagram(p->udptl);
+}
+
 /*! \brief Change the T38 state on a SIP dialog */
 static void change_t38_state(struct sip_pvt *p, int state)
 {
 	int old = p->t38.state;
 	struct ast_channel *chan = p->owner;
 	enum ast_control_t38 message = 0;
+	struct ast_control_t38_parameters parameters = { 0, };
 
 	/* Don't bother changing if we are already in the state wanted */
 	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>");
 
@@ -4330,16 +4368,20 @@
 		return;
 
 	/* Given the state requested and old state determine what control frame we want to queue up */
-	if (state == T38_PEER_REINVITE)
-		message = AST_T38_REQUEST_NEGOTIATE;
-	else if (state == T38_ENABLED)
-		message = AST_T38_NEGOTIATED;
-	else if (state == T38_DISABLED && old == T38_ENABLED)
-		message = AST_T38_TERMINATED;
+	if (state == T38_PEER_REINVITE) {
+		message = parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
+		fill_t38_parameters(p->t38.peercapability, &parameters, p);
+	} else if (state == T38_ENABLED) {
+		message = parameters.request_response = AST_T38_NEGOTIATED;
+		fill_t38_parameters(p->t38.jointcapability, &parameters, p);
+	} else if (state == T38_DISABLED && old == T38_ENABLED)
+		message = parameters.request_response = AST_T38_TERMINATED;
 	else if (state == T38_DISABLED && old == T38_LOCAL_REINVITE)
-		message = AST_T38_REFUSED;
+		message = parameters.request_response = AST_T38_REFUSED;
 
 	/* Woot we got a message, create a control frame and send it on! */
+	if (parameters.request_response)
+		ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
 	if (message)
 		ast_queue_control_data(chan, AST_CONTROL_T38, &message, sizeof(message));
 }
@@ -4349,12 +4391,16 @@
 {
 	p->t38.capability = global_t38_capability;
 	if (p->udptl) {
-		if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_FEC )
+		if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) == SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY) {
+                        ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY);
+			p->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
+		} else if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) == SIP_PAGE2_T38SUPPORT_UDPTL_FEC) {
+			ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_FEC);
 			p->t38.capability |= T38FAX_UDP_EC_FEC;
-		else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_REDUNDANCY )
-			p->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
-		else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_NONE )
+		} else if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) == SIP_PAGE2_T38SUPPORT_UDPTL) {
+			ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE);
 			p->t38.capability |= T38FAX_UDP_EC_NONE;
+		}
 		p->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
 	}
 }
@@ -5445,9 +5491,6 @@
 
 		ast_setstate(ast, AST_STATE_UP);
 		ast_debug(1, "SIP answering channel: %s\n", ast->name);
-		if (p->t38.state == T38_PEER_DIRECT) {
-			change_t38_state(p, T38_ENABLED);
-		}
 		ast_rtp_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);
@@ -5487,7 +5530,7 @@
 					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) {
+				} else if (p->t38.state == T38_ENABLED) {
 					change_t38_state(p, T38_DISABLED);
 					transmit_reinvite_with_sdp(p, FALSE, FALSE);
 				} else {
@@ -5677,6 +5720,90 @@
 	return res;
 }
 
+/*! \brief Helper function which updates T.38 capability information and triggers a reinvite */
+static void interpret_t38_parameters(struct sip_pvt *p, enum ast_control_t38 request_response, const struct ast_control_t38_parameters *parameters)
+{
+	if (parameters) {
+		if (!parameters->version) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_VERSION_0;
+		} else if (parameters->version == 1) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_VERSION_1;
+		}
+
+		if (parameters->rate == AST_T38_RATE_14400) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+		} else if (parameters->rate == AST_T38_RATE_12000) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+		} else if (parameters->rate == AST_T38_RATE_9600) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+		} else if (parameters->rate == AST_T38_RATE_7200) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+		} else if (parameters->rate == AST_T38_RATE_4800) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_4800 | T38FAX_RATE_2400;
+		} else if (parameters->rate == AST_T38_RATE_2400) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_2400;
+		}
+
+		if (parameters->rate_management == AST_T38_RATE_MANAGEMENT_TRANSFERED_TCF) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
+		} else if (parameters->rate_management == AST_T38_RATE_MANAGEMENT_LOCAL_TCF) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_MANAGEMENT_LOCAL_TCF;
+		}
+
+		if (parameters->fill_bit_removal) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_FILL_BIT_REMOVAL;
+		} else {
+			p->t38.capability = p->t38.jointcapability &= ~T38FAX_FILL_BIT_REMOVAL;
+		}
+
+		if (parameters->transcoding_mmr) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_TRANSCODING_MMR;
+		} else {
+			p->t38.capability = p->t38.jointcapability &= ~T38FAX_TRANSCODING_MMR;
+		}
+
+		if (parameters->transcoding_jbig) {
+			p->t38.capability = p->t38.jointcapability |= T38FAX_TRANSCODING_JBIG;
+		} else {
+			p->t38.capability = p->t38.jointcapability &= ~T38FAX_TRANSCODING_JBIG;
+		}
+
+		if (p->udptl && request_response == AST_T38_REQUEST_NEGOTIATE) {
+			ast_udptl_set_local_max_datagram(p->udptl, parameters->max_datagram ? parameters->max_datagram : 400);
+		}
+	}
+
+	switch (request_response) {
+	case AST_T38_NEGOTIATED:
+	case AST_T38_REQUEST_NEGOTIATE:         /* Request T38 */
+		if (p->t38.state == T38_PEER_REINVITE) {
+			AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
+			change_t38_state(p, T38_ENABLED);
+			transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
+		} else if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT) && p->t38.state != T38_ENABLED) {
+			change_t38_state(p, T38_LOCAL_REINVITE);
+			if (!p->pendinginvite) {
+				transmit_reinvite_with_sdp(p, TRUE, FALSE);
+			} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
+				ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
+			}
+		}
+		break;
+	case AST_T38_TERMINATED:
+	case AST_T38_REFUSED:
+	case AST_T38_REQUEST_TERMINATE:         /* Shutdown T38 */
+		if (p->t38.state == T38_PEER_REINVITE) {
+			AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
+			change_t38_state(p, T38_DISABLED);
+			transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
+		} else if (p->t38.state == T38_ENABLED)
+			transmit_reinvite_with_sdp(p, FALSE, FALSE);
+		break;
+	default:
+		break;
+	}
+}
+
 /*! \brief Play indication to user 
  * With SIP a lot of indications is sent as messages, letting the device play
    the indication - busy signal, congestion etc 
@@ -5765,35 +5892,15 @@
 		if (datalen != sizeof(enum ast_control_t38)) {
 			ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38. Expected %d, got %d\n", (int)sizeof(enum ast_control_t38), (int)datalen);
 		} else {
-			switch (*((enum ast_control_t38 *) data)) {
-			case AST_T38_NEGOTIATED:
-			case AST_T38_REQUEST_NEGOTIATE:		/* Request T38 */
-				if (p->t38.state == T38_PEER_REINVITE) {
-					AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
-					change_t38_state(p, T38_ENABLED);
-					transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
-				} else if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT) && p->t38.state != T38_ENABLED) {
-					change_t38_state(p, T38_LOCAL_REINVITE);
-					if (!p->pendinginvite) {
-						transmit_reinvite_with_sdp(p, TRUE, FALSE);
-					} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
-						ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
-					}
-				}
-				break;
-			case AST_T38_TERMINATED:
-			case AST_T38_REFUSED:
-			case AST_T38_REQUEST_TERMINATE:		/* Shutdown T38 */
-				if (p->t38.state == T38_PEER_REINVITE) {
-					AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
-					change_t38_state(p, T38_DISABLED);
-					transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
-				} else if (p->t38.state == T38_ENABLED)
-					transmit_reinvite_with_sdp(p, FALSE, FALSE);
-				break;
-			default:
-				break;
-			}
+			interpret_t38_parameters(p, *((enum ast_control_t38 *) data), NULL);
+		}
+		break;
+	case AST_CONTROL_T38_PARAMETERS:
+		if (datalen != sizeof(struct ast_control_t38_parameters)) {
+			ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38_PARAMETERS. Expected %d, got %d\n", (int)sizeof(struct ast_control_t38_parameters), (int)datalen);
+		} else {
+			const struct ast_control_t38_parameters *parameters = data;
+			interpret_t38_parameters(p, parameters->request_response, parameters);
 		}
 		break;
 	case AST_CONTROL_SRCUPDATE:
@@ -6203,7 +6310,7 @@
 	if (f && (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
 		f = ast_dsp_process(p->owner, p->vad, f);
 		if (f && f->frametype == AST_FRAME_DTMF) {
-			if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && f->subclass == 'f') {
+			if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT) && f->subclass == 'f') {
 				ast_debug(1, "Fax CNG detected on %s\n", ast->name);
 				*faxdetect = 1;
 			} else {
@@ -6228,7 +6335,7 @@
 
 	/* If we are NOT bridged to another channel, and we have detected fax tone we issue T38 re-invite to a peer */
 	/* If we are bridged then it is the responsibility of the SIP device to issue T38 re-invite if it detects CNG or fax preamble */
-	if (faxdetected && ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) {
+	if (faxdetected && ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) {
 		if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
 			if (!p->pendinginvite) {
 				ast_debug(3, "Sending reinvite on SIP (%s) for T.38 negotiation.\n", ast->name);
@@ -7574,7 +7681,9 @@
 				found = 1;
 				ast_debug(3, "FaxMaxDatagram: %d\n", x);
 				ast_udptl_set_far_max_datagram(p->udptl, x);
-				ast_udptl_set_local_max_datagram(p->udptl, x);
+				if (!ast_udptl_get_local_max_datagram(p->udptl)) {
+					ast_udptl_set_local_max_datagram(p->udptl, x);
+				}
 			} else if ((strncmp(a, "T38FaxFillBitRemoval", 20) == 0)) {
 				found = 1;
 				if(sscanf(a, "T38FaxFillBitRemoval:%d", &x) == 1) {
@@ -7646,8 +7755,6 @@
 		} else if (t38action == SDP_T38_INITIATE) {
 			if (p->owner && p->lastinvite) {
 				change_t38_state(p, T38_PEER_REINVITE); /* T38 Offered in re-invite from remote party */
-			} else {
-				change_t38_state(p, T38_PEER_DIRECT); /* T38 Offered directly from peer in first invite */
 			}
 		}
 	} else {
@@ -8875,13 +8982,6 @@
 		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);
-		}
-#endif
 
 		/* Check if we need audio */
 		if (capability & AST_FORMAT_AUDIO_MASK)
@@ -9082,8 +9182,10 @@
 		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 (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY)
+			ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:t38UDPRedundancy\r\n");
+		else if (p->t38.jointcapability & T38FAX_UDP_EC_FEC)
+			ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:t38UDPFEC\r\n");
 	}
 
 	if (m_audio->len - m_audio->used < 2 || m_video->len - m_video->used < 2 ||
@@ -9209,7 +9311,7 @@
 			ast_rtp_codec_setpref(p->rtp, &p->prefs);
 		}
 		try_suggested_sip_codec(p);
-		if (p->t38.state == T38_PEER_DIRECT || p->t38.state == T38_ENABLED) {
+		if (p->t38.state == T38_ENABLED) {
 			add_sdp(&resp, p, oldsdp, TRUE, TRUE);
 		} else {
 			add_sdp(&resp, p, oldsdp, TRUE, FALSE);
@@ -12526,6 +12628,11 @@
 	ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
 
+	if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->udptl) {
+		set_t38_capabilities(p);
+		p->t38.jointcapability = p->t38.capability;
+	}
+
 	/* Copy SIP extensions profile to peer */
 	/* XXX is this correct before a successful auth ? */
 	if (p->sipoptions)
@@ -13975,11 +14082,7 @@
 		ast_cli(fd, "  Insecure     : %s\n", insecure2str(ast_test_flag(&peer->flags[0], SIP_INSECURE)));
 		ast_cli(fd, "  Nat          : %s\n", nat2str(ast_test_flag(&peer->flags[0], SIP_NAT)));
 		ast_cli(fd, "  ACL          : %s\n", cli_yesno(peer->ha != NULL));
-		ast_cli(fd, "  T38 pt UDPTL : %s\n", cli_yesno(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_UDPTL)));
-#ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
-		ast_cli(fd, "  T38 pt RTP   : %s\n", cli_yesno(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_RTP)));
-		ast_cli(fd, "  T38 pt TCP   : %s\n", cli_yesno(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_TCP)));
-#endif
+		ast_cli(fd, "  T38 pt UDPTL : %s\n", cli_yesno(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT)));
 		ast_cli(fd, "  CanReinvite  : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_CAN_REINVITE)));
 		ast_cli(fd, "  PromiscRedir : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_PROMISCREDIR)));
 		ast_cli(fd, "  User=Phone   : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_USEREQPHONE)));
@@ -14531,11 +14634,8 @@
 	ast_cli(a->fd, "  Call Events:            %s\n", global_callevents ? "On" : "Off");
 	ast_cli(a->fd, "  Auth. Failure Events:   %s\n", global_authfailureevents ? "On" : "Off");
 
-	ast_cli(a->fd, "  T38 fax pt UDPTL:       %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_UDPTL)));
-#ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
-	ast_cli(a->fd, "  T38 fax pt RTP:         %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_RTP)));
-	ast_cli(a->fd, "  T38 fax pt TCP:         %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_TCP)));
-#endif
+	ast_cli(a->fd, "  T38 fax pt UDPTL:       %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT)));
+
 	if (!realtimepeers && !realtimeregs)
 		ast_cli(a->fd, "  SIP realtime:           Disabled\n" );
 	else
@@ -18395,6 +18495,8 @@
 		if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && !p->udptl && (p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr))) {
 			set_t38_capabilities(p);
 			p->t38.jointcapability = p->t38.capability;
+			set_t38_capabilities(p);
+			p->t38.jointcapability = p->t38.capability;
 		}
 
 		/* We have a succesful authentication, process the SDP portion if there is one */
@@ -21631,16 +21733,24 @@
 		ast_set_flag(&mask[1], SIP_PAGE2_IGNORESDPVERSION);
 		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_IGNORESDPVERSION);
 	} else if (!strcasecmp(v->name, "t38pt_udptl")) {
-		ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_UDPTL);
-		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_UDPTL);
-#ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
-	} else if (!strcasecmp(v->name, "t38pt_rtp")) {
-		ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_RTP);
-		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_RTP);
-	} else if (!strcasecmp(v->name, "t38pt_tcp")) {
-		ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_TCP);
-		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_TCP);
-#endif
+		char buf[16], *word, *next = buf;
+
+		ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT);
+
+		ast_copy_string(buf, v->value, sizeof(buf));
+
+		while ((word = strsep(&next, ","))) {
+			if (ast_true(word) || !strcasecmp(word, "fec")) {
+				ast_clear_flag(&flags[1], SIP_PAGE2_T38SUPPORT);
+				ast_set_flag(&flags[1], SIP_PAGE2_T38SUPPORT_UDPTL_FEC);
+			} else if (!strcasecmp(word, "redundancy")) {
+				ast_clear_flag(&flags[1], SIP_PAGE2_T38SUPPORT);
+				ast_set_flag(&flags[1], SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY);
+			} else if (!strcasecmp(word, "none")) {
+				ast_clear_flag(&flags[1], SIP_PAGE2_T38SUPPORT);
+				ast_set_flag(&flags[1], SIP_PAGE2_T38SUPPORT_UDPTL);
+			}
+		}
 	} else if (!strcasecmp(v->name, "rfc2833compensate")) {
 		ast_set_flag(&mask[1], SIP_PAGE2_RFC2833_COMPENSATE);
 		ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RFC2833_COMPENSATE);

Modified: branches/1.6.1/configs/sip.conf.sample
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.1/configs/sip.conf.sample?view=diff&rev=203703&r1=203702&r2=203703
==============================================================================
--- branches/1.6.1/configs/sip.conf.sample (original)
+++ branches/1.6.1/configs/sip.conf.sample Fri Jun 26 14:31:36 2009
@@ -422,11 +422,13 @@
 ; Setting this to yes, enables T.38 fax (UDPTL) passthrough on SIP to SIP calls, provided
 ; both parties have T38 support enabled in their Asterisk configuration 
 ; This has to be enabled in the general section for all devices to work. You can then
-; disable it on a per device basis. 
-;
-; T.38 faxing only works in SIP to SIP calls, with no local or agent channel being used.
-;
-; t38pt_udptl = yes            ; Default false
+; disable it on a per device basis.
+; T.38 faxing only works in SIP to SIP calls. It defaults to off.
+;
+; t38pt_udptl = yes            ; Enables T.38 with FEC error correction.
+; t38pt_udptl = yes,fec        ; Enables T.38 with FEC error correction.
+; t38pt_udptl = yes,redundancy ; Enables T.38 with redundancy error correction.
+; t38pt_udptl = yes,none       ; Enables T.38 with no error correction.
 ;
 ;----------------------------------------- OUTBOUND SIP REGISTRATIONS  ------------------------
 ; Asterisk can register as a SIP user agent to a SIP proxy (provider)

Modified: branches/1.6.1/include/asterisk/frame.h
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.1/include/asterisk/frame.h?view=diff&rev=203703&r1=203702&r2=203703
==============================================================================
--- branches/1.6.1/include/asterisk/frame.h (original)
+++ branches/1.6.1/include/asterisk/frame.h Fri Jun 26 14:31:36 2009
@@ -317,6 +317,7 @@
 	AST_CONTROL_VIDUPDATE = 18,	/*!< Indicate video frame update */
 	AST_CONTROL_T38 = 19,		/*!< T38 state change request/notification */
 	AST_CONTROL_SRCUPDATE = 20,     /*!< Indicate source of media has changed */
+	AST_CONTROL_T38_PARAMETERS = 24, /*!< T38 state change request/notification with parameters */
 };
 
 enum ast_control_t38 {
@@ -325,6 +326,31 @@
 	AST_T38_NEGOTIATED,		/*!< T38 negotiated (fax mode) */
 	AST_T38_TERMINATED,		/*!< T38 terminated (back to voice) */
 	AST_T38_REFUSED			/*!< T38 refused for some reason (usually rejected by remote end) */
+};
+
+enum ast_control_t38_rate {
+	AST_T38_RATE_2400 = 0,
+	AST_T38_RATE_4800,
+	AST_T38_RATE_7200,
+	AST_T38_RATE_9600,
+	AST_T38_RATE_12000,
+	AST_T38_RATE_14400,
+};
+
+enum ast_control_t38_rate_management {
+	AST_T38_RATE_MANAGEMENT_TRANSFERED_TCF = 0,
+	AST_T38_RATE_MANAGEMENT_LOCAL_TCF,
+};
+
+struct ast_control_t38_parameters {
+	enum ast_control_t38 request_response;                /*!< Request or response of the T38 control frame */
+	unsigned int version;                                 /*!< Supported T.38 version */
+	unsigned int max_datagram;                            /*!< Maximum datagram size supported */
+	enum ast_control_t38_rate rate;                       /*!< Maximum fax rate supported */
+	enum ast_control_t38_rate_management rate_management; /*!< Rate management setting */
+	unsigned int fill_bit_removal:1;                      /*!< Set if fill bit removal should be used */
+	unsigned int transcoding_mmr:1;                       /*!< Set if MMR transcoding should be used */
+	unsigned int transcoding_jbig:1;                      /*!< Set if JBIG transcoding should be used */
 };
 
 #define AST_SMOOTHER_FLAG_G729		(1 << 0)

Modified: branches/1.6.1/main/channel.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.1/main/channel.c?view=diff&rev=203703&r1=203702&r2=203703
==============================================================================
--- branches/1.6.1/main/channel.c (original)
+++ branches/1.6.1/main/channel.c Fri Jun 26 14:31:36 2009
@@ -3040,6 +3040,7 @@
 	case AST_CONTROL_ANSWER:
 	case AST_CONTROL_HANGUP:
 	case AST_CONTROL_T38:
+	case AST_CONTROL_T38_PARAMETERS:
 		return 0;
 
 	case AST_CONTROL_CONGESTION:
@@ -3136,6 +3137,7 @@
 	case AST_CONTROL_HOLD:
 	case AST_CONTROL_UNHOLD:
 	case AST_CONTROL_T38:
+	case AST_CONTROL_T38_PARAMETERS:
 		/* Nothing left to do for these. */
 		res = 0;
 		break;
@@ -4751,6 +4753,7 @@
 			case AST_CONTROL_VIDUPDATE:
 			case AST_CONTROL_SRCUPDATE:
 			case AST_CONTROL_T38:
+			case AST_CONTROL_T38_PARAMETERS:
 				ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
 				if (jb_in_use) {
 					ast_jb_empty_and_reset(c0, c1);

Modified: branches/1.6.1/main/frame.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.1/main/frame.c?view=diff&rev=203703&r1=203702&r2=203703
==============================================================================
--- branches/1.6.1/main/frame.c (original)
+++ branches/1.6.1/main/frame.c Fri Jun 26 14:31:36 2009
@@ -853,6 +853,25 @@
 			}
 			snprintf(subclass, sizeof(subclass), "T38/%s", message);
 			break;
+		case AST_CONTROL_T38_PARAMETERS:
+			if (f->datalen != sizeof(struct ast_control_t38_parameters *)) {
+				message = "Invalid";
+			} else {
+				struct ast_control_t38_parameters *parameters = f->data.ptr;
+				enum ast_control_t38 state = parameters->request_response;
+				if (state == AST_T38_REQUEST_NEGOTIATE)
+					message = "Negotiation Requested";
+				else if (state == AST_T38_REQUEST_TERMINATE)
+					message = "Negotiation Request Terminated";
+				else if (state == AST_T38_NEGOTIATED)
+					message = "Negotiated";
+				else if (state == AST_T38_TERMINATED)
+					message = "Terminated";
+				else if (state == AST_T38_REFUSED)
+					message = "Refused";
+			}
+			snprintf(subclass, sizeof(subclass), "T38_Parameters/%s", message);
+			break;
 		case -1:
 			strcpy(subclass, "Stop generators");
 			break;

Modified: branches/1.6.1/main/rtp.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.1/main/rtp.c?view=diff&rev=203703&r1=203702&r2=203703
==============================================================================
--- branches/1.6.1/main/rtp.c (original)
+++ branches/1.6.1/main/rtp.c Fri Jun 26 14:31:36 2009
@@ -3998,7 +3998,8 @@
 			    (fr->subclass == AST_CONTROL_UNHOLD) ||
 			    (fr->subclass == AST_CONTROL_VIDUPDATE) ||
 			    (fr->subclass == AST_CONTROL_T38) ||
-			    (fr->subclass == AST_CONTROL_SRCUPDATE)) {
+			    (fr->subclass == AST_CONTROL_SRCUPDATE) ||
+			    (fr->subclass == AST_CONTROL_T38_PARAMETERS)) {
 				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)
@@ -4238,7 +4239,8 @@
 			    (fr->subclass == AST_CONTROL_UNHOLD) ||
 			    (fr->subclass == AST_CONTROL_VIDUPDATE) ||
 			    (fr->subclass == AST_CONTROL_T38) ||
-			    (fr->subclass == AST_CONTROL_SRCUPDATE)) {
+			    (fr->subclass == AST_CONTROL_SRCUPDATE) ||
+			    (fr->subclass == AST_CONTROL_T38_PARAMETERS)) {
 				/* If we are going on hold, then break callback mode and P2P bridging */
 				if (fr->subclass == AST_CONTROL_HOLD) {
 					if (p0_callback)




More information about the svn-commits mailing list