[asterisk-commits] file: branch file/gulp_fax r394190 - /team/file/gulp_fax/res/res_sip_t38.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jul 12 13:16:18 CDT 2013


Author: file
Date: Fri Jul 12 13:16:17 2013
New Revision: 394190

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=394190
Log:
Add parsing of T.38 SDP, negotiation, and the state machine. Next up is moving stuff to use the state machine.

Modified:
    team/file/gulp_fax/res/res_sip_t38.c

Modified: team/file/gulp_fax/res/res_sip_t38.c
URL: http://svnview.digium.com/svn/asterisk/team/file/gulp_fax/res/res_sip_t38.c?view=diff&rev=394190&r1=394189&r2=394190
==============================================================================
--- team/file/gulp_fax/res/res_sip_t38.c (original)
+++ team/file/gulp_fax/res/res_sip_t38.c Fri Jul 12 13:16:17 2013
@@ -157,6 +157,55 @@
 	return datastore->data;
 }
 
+/*! \brief Helper function for changing the T.38 state */
+static void t38_change_state(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+	struct t38_state *state, enum t38state new_state)
+{
+	enum t38state old_state = state->state;
+	struct ast_control_t38_parameters parameters = { .request_response = 0, };
+
+	if (old_state == new_state) {
+		return;
+	}
+
+	state->state = new_state;
+	ast_debug(2, "T.38 state changed to '%d' from '%d' on channel '%s'\n", new_state, old_state, ast_channel_name(session->channel));
+
+	if (!session->channel) {
+		return;
+	}
+
+	switch (new_state) {
+	case T38_PEER_REINVITE:
+		parameters = state->their_parms;
+		parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
+		parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
+		ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
+		break;
+	case T38_ENABLED:
+		parameters = state->their_parms;
+		parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
+		parameters.request_response = AST_T38_NEGOTIATED;
+		ast_udptl_set_tag(session_media->udptl, "%s", ast_channel_name(session->channel));
+		break;
+	case T38_REJECTED:
+	case T38_DISABLED:
+		if (old_state == T38_ENABLED) {
+			parameters.request_response = AST_T38_TERMINATED;
+		} else if (old_state == T38_LOCAL_REINVITE) {
+			parameters.request_response = AST_T38_REFUSED;
+		}
+		break;
+	case T38_LOCAL_REINVITE:
+		/* wait until we get a peer response before responding to local reinvite */
+		break;
+	}
+
+	if (parameters.request_response) {
+		ast_queue_control_data(session->channel, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
+	}
+}
+
 /*! \brief Initializes UDPTL support on a session, only done when actually needed */
 static int t38_initialize_session(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
 {
@@ -224,8 +273,7 @@
 			state->our_parms = *parameters;
 			ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
 			/* XXX Need to suppress other streams temporarily */
-			/* XXX Need to change state to local reinvite */
-			/* XXX Need to send reinvite */
+			t38_change_state(data->session, session_media, state, T38_LOCAL_REINVITE);
 			ast_sip_session_refresh(data->session, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1);
 		}
 		break;
@@ -379,6 +427,94 @@
 static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
 					 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
 {
+	char host[NI_MAXHOST];
+	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
+	struct t38_state *state;
+	unsigned int attr_i;
+
+	if (!session->endpoint->t38udptl) {
+		return -1;
+	}
+
+	ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));
+
+	/* Ensure that the address provided is valid */
+	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) {
+		/* The provided host was actually invalid so we error out this negotiation */
+		return -1;
+	}
+
+	if (t38_initialize_session(session, session_media)) {
+		return -1;
+	}
+
+	if (!(state = t38_state_get_or_alloc(session))) {
+		return 0;
+	}
+
+	for (attr_i = 0; attr_i < stream->attr_count; attr_i++) {
+		pjmedia_sdp_attr *attr = stream->attr[attr_i];
+
+		if (!pj_stricmp2(&attr->name, "t38faxmaxbuffer")) {
+			/* This is purposely left empty, it is unused */
+		} else if (!pj_stricmp2(&attr->name, "t38maxbitrate") || !pj_stricmp2(&attr->name, "t38faxmaxrate")) {
+			switch (pj_strtoul(&attr->value)) {
+			case 14400:
+				state->their_parms.rate = AST_T38_RATE_14400;
+				break;
+			case 12000:
+				state->their_parms.rate = AST_T38_RATE_12000;
+				break;
+			case 9600:
+				state->their_parms.rate = AST_T38_RATE_9600;
+				break;
+			case 7200:
+				state->their_parms.rate = AST_T38_RATE_7200;
+				break;
+			case 4800:
+				state->their_parms.rate = AST_T38_RATE_4800;
+				break;
+			case 2400:
+				state->their_parms.rate = AST_T38_RATE_2400;
+				break;
+			}
+		} else if (!pj_stricmp2(&attr->name, "t38faxversion")) {
+			state->their_parms.version = pj_strtoul(&attr->value);
+		} else if (!pj_stricmp2(&attr->name, "t38faxmaxdatagram") || !pj_stricmp2(&attr->name, "t38maxdatagram")) {
+			if (session->endpoint->t38udptl_maxdatagram) {
+				ast_udptl_set_far_max_datagram(session_media->udptl, session->endpoint->t38udptl_maxdatagram);
+			} else {
+				ast_udptl_set_far_max_datagram(session_media->udptl, pj_strtoul(&attr->value));
+			}
+		} else if (!pj_stricmp2(&attr->name, "t38faxfillbitremoval")) {
+			state->their_parms.fill_bit_removal = 1;
+		} else if (!pj_stricmp2(&attr->name, "t38faxtranscodingmmr")) {
+			state->their_parms.transcoding_mmr = 1;
+		} else if (!pj_stricmp2(&attr->name, "t38faxtranscodingjbig")) {
+			state->their_parms.transcoding_jbig = 1;
+		} else if (!pj_stricmp2(&attr->name, "t38faxratemanagement")) {
+			if (!pj_stricmp2(&attr->value, "localTCF")) {
+				state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
+			} else if (!pj_stricmp2(&attr->value, "transferredTCF")) {
+				state->their_parms.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
+			}
+		} else if (!pj_stricmp2(&attr->name, "t38faxudpec")) {
+			if (!pj_stricmp2(&attr->value, "t38UDPRedundancy")) {
+				ast_udptl_set_error_correction_scheme(session_media->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY);
+			} else if (!pj_stricmp2(&attr->value, "t38UDPFEC")) {
+				ast_udptl_set_error_correction_scheme(session_media->udptl, UDPTL_ERROR_CORRECTION_FEC);
+			} else {
+				ast_udptl_set_error_correction_scheme(session_media->udptl, UDPTL_ERROR_CORRECTION_NONE);
+			}
+		}
+
+	}
+
+	/* If we aren't the one who offered T.38 it is them, so change state */
+	if (state->state == T38_DISABLED) {
+		t38_change_state(session, session_media, state, T38_PEER_REINVITE);
+	}
+
 	return 0;
 }
 
@@ -402,8 +538,14 @@
 	char tmp[512];
 	pj_str_t stmp;
 
-	if (!session_media->udptl) {
+	if (!session->endpoint->t38udptl) {
 		return 0;
+	} else if (!(state = t38_state_get_or_alloc(session))) {
+		return 0;
+	} else if ((state->state != T38_LOCAL_REINVITE) && (state->state != T38_PEER_REINVITE)) {
+		return 0;
+	} else if (t38_initialize_session(session, session_media)) {
+		return -1;
 	}
 
 	if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
@@ -433,8 +575,6 @@
 	media->desc.port_count = 1;
 	media->desc.fmt[media->desc.fmt_count++] = STR_T38;
 
-	state = t38_state_get_or_alloc(session);
-
 	snprintf(tmp, sizeof(tmp), "%d", state->our_parms.version);
 	media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxVersion", pj_cstr(&stmp, tmp));
 
@@ -486,6 +626,24 @@
 				       const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
 				       const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
 {
+	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
+	char host[NI_MAXHOST];
+
+	if (!session_media->udptl) {
+		return 0;
+	}
+
+	ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
+
+	/* Ensure that the address provided is valid */
+	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
+		/* The provided host was actually invalid so we error out this negotiation */
+		return -1;
+	}
+
+	ast_sockaddr_set_port(addrs, remote_stream->desc.port);
+	ast_udptl_set_peer(session_media->udptl, addrs);
+
 	return 0;
 }
 




More information about the asterisk-commits mailing list