[svn-commits] file: branch file/gulp_fax r394190 - /team/file/gulp_fax/res/res_sip_t38.c
SVN commits to the Digium repositories
svn-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, ¶meters, 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 svn-commits
mailing list