diff --git a/doc/CHANGES-staging/res_fax_negotiate_both b/doc/CHANGES-staging/res_fax_negotiate_both new file mode 100644 index 0000000000..73be756028 --- /dev/null +++ b/doc/CHANGES-staging/res_fax_negotiate_both @@ -0,0 +1,7 @@ +Subject: res_fax + +Added configuration option "negotiate_both". This option is only used +when a gateway is enabled, and a v21 preamble is detected. If this option +is enabled, once a preamble is detected Asterisk will initiate negotiation +requests to both T.38 enabled endpoint versus waiting, and forwarding a +request from an initiating endpoint. Defaults to disabled. diff --git a/include/asterisk/res_fax.h b/include/asterisk/res_fax.h index c1dd37847c..dc455bbfd4 100644 --- a/include/asterisk/res_fax.h +++ b/include/asterisk/res_fax.h @@ -189,6 +189,9 @@ struct ast_fax_session_details { int faxdetect_flags; /*! Non-zero if T.38 is negotiated */ int is_t38_negotiated; + /*! Upon v21 detection the gateway sends negotiation requests to both + T.38 endpoints, and do not wait on the "other" side to initiate */ + int negotiate_both; }; struct ast_fax_tech; diff --git a/res/res_fax.c b/res/res_fax.c index 7d9cb4e8ca..ebb2b46266 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -226,6 +226,9 @@ R/W The timeout used for T.38 negotiation. + + R/W Upon v21 detection allow gateway to send negotiation requests to both T.38 endpoints, and do not wait on the "other" side to initiate (yes|no) + @@ -722,6 +725,7 @@ static struct ast_fax_session_details *session_details_new(void) d->gateway_id = -1; d->faxdetect_id = -1; d->gateway_timeout = 0; + d->negotiate_both = 0; return d; } @@ -3023,6 +3027,22 @@ static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, str enum ast_t38_state state_other; enum ast_t38_state state_active; struct ast_frame *fp; + struct ast_fax_session_details *details; + int negotiate_both = 0; + + /* + * The default behavior is to wait for the active endpoint to initiate negotiation. + * Find out if this has been overridden. If so, instead of waiting have Asterisk + * initiate the negotiation requests out to both endpoints. + */ + details = find_or_create_details(active); + if (details) { + negotiate_both = details->negotiate_both; + ao2_ref(details, -1); + } else { + ast_log(LOG_WARNING, "Detect v21 - no session details for channel '%s'\n", + ast_channel_name(chan)); + } destroy_v21_sessions(gateway); @@ -3039,7 +3059,7 @@ static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, str } /* May be called endpoint is improperly configured to rely on the calling endpoint * to initiate T.38 re-INVITEs, send T.38 negotiation request to called endpoint */ - if (state_active == T38_STATE_UNKNOWN) { + if (negotiate_both && state_active == T38_STATE_UNKNOWN) { ast_debug(1, "sending T.38 negotiation request to %s\n", ast_channel_name(active)); if (active == chan) { ast_channel_unlock(chan); @@ -4557,6 +4577,8 @@ static int acf_faxopt_read(struct ast_channel *chan, const char *cmd, char *data ast_fax_modem_to_str(details->modems, buf, len); } else if (!strcasecmp(data, "t38timeout")) { snprintf(buf, len, "%u", details->t38timeout); + } else if (!strcasecmp(data, "negotiate_both")) { + ast_copy_string(buf, details->negotiate_both != -1 ? "yes" : "no", len); } else { ast_log(LOG_WARNING, "channel '%s' can't read FAXOPT(%s) because it is unhandled!\n", ast_channel_name(chan), data); res = -1; @@ -4695,6 +4717,8 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat } } else if ((!strcasecmp(data, "modem")) || (!strcasecmp(data, "modems"))) { update_modem_bits(&details->modems, value); + } else if (!strcasecmp(data, "negotiate_both")) { + details->negotiate_both = ast_true(ast_skip_blanks(value)); } else { ast_log(LOG_WARNING, "channel '%s' set FAXOPT(%s) to '%s' is unhandled!\n", ast_channel_name(chan), data, value); res = -1;