diff options
Diffstat (limited to 'res/res_fax.c')
-rw-r--r-- | res/res_fax.c | 132 |
1 files changed, 85 insertions, 47 deletions
diff --git a/res/res_fax.c b/res/res_fax.c index 431e7086a..8073f2d6e 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -53,6 +53,10 @@ * \ingroup applications */ +/*** MODULEINFO + <support_level>core</support_level> + ***/ + #include "asterisk.h" ASTERISK_FILE_VERSION(__FILE__, "$Revision$") @@ -253,6 +257,8 @@ struct fax_gateway { int framehook; /*! \brief bridged */ int bridged:1; + /*! \brief 1 if a v21 preamble has been detected */ + int detected_v21:1; /*! \brief a flag to track the state of our negotiation */ enum ast_t38_state t38_state; /*! \brief original audio formats */ @@ -2407,10 +2413,10 @@ static struct fax_gateway *fax_gateway_new(struct ast_fax_session_details *detai gateway->framehook = -1; ast_dsp_set_features(gateway->chan_dsp, DSP_FEATURE_FAX_DETECT); - ast_dsp_set_faxmode(gateway->chan_dsp, DSP_FAXMODE_DETECT_CED); + ast_dsp_set_faxmode(gateway->chan_dsp, DSP_FAXMODE_DETECT_V21); ast_dsp_set_features(gateway->peer_dsp, DSP_FEATURE_FAX_DETECT); - ast_dsp_set_faxmode(gateway->peer_dsp, DSP_FAXMODE_DETECT_CED); + ast_dsp_set_faxmode(gateway->peer_dsp, DSP_FAXMODE_DETECT_V21); details->caps = AST_FAX_TECH_GATEWAY; if (!(gateway->s = fax_session_reserve(details, &gateway->token))) { @@ -2465,57 +2471,68 @@ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session return 0; } -static struct ast_frame *fax_gateway_detect_ced(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *active, struct ast_frame *f) +static struct ast_frame *fax_gateway_request_t38(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_frame *f) { - struct ast_frame *dfr = ast_frdup(f); - struct ast_dsp *active_dsp = (active == chan) ? gateway->chan_dsp : gateway->peer_dsp; - struct ast_channel *other = (active == chan) ? peer : chan; + struct ast_frame *fp; + struct ast_control_t38_parameters t38_parameters = { + .request_response = AST_T38_REQUEST_NEGOTIATE, + }; + struct ast_frame control_frame = { + .src = "res_fax", + .frametype = AST_FRAME_CONTROL, + .datalen = sizeof(t38_parameters), + .subclass.integer = AST_CONTROL_T38_PARAMETERS, + .data.ptr = &t38_parameters, + }; - if (!dfr) { + struct ast_fax_session_details *details = find_details(chan); + + if (!details) { + ast_log(LOG_ERROR, "no FAX session details found on chan %s for T.38 gateway session, odd\n", chan->name); + ast_framehook_detach(chan, gateway->framehook); return f; } - if (!(dfr = ast_dsp_process(active, active_dsp, dfr))) { + t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters); + ao2_ref(details, -1); + + if (!(fp = ast_frisolate(&control_frame))) { + ast_log(LOG_ERROR, "error generating T.38 request control frame on chan %s for T.38 gateway session\n", chan->name); return f; } - if (dfr->frametype == AST_FRAME_DTMF && dfr->subclass.integer == 'e') { - if (ast_channel_get_t38_state(other) == T38_STATE_UNKNOWN) { - struct ast_control_t38_parameters t38_parameters = { - .request_response = AST_T38_REQUEST_NEGOTIATE, - }; - struct ast_frame control_frame = { - .src = "res_fax", - .frametype = AST_FRAME_CONTROL, - .datalen = sizeof(t38_parameters), - .subclass.integer = AST_CONTROL_T38_PARAMETERS, - .data.ptr = &t38_parameters, - }; + gateway->t38_state = T38_STATE_NEGOTIATING; + gateway->timeout_start = ast_tvnow(); - struct ast_fax_session_details *details = find_details(chan); - ast_frfree(dfr); + ast_debug(1, "requesting T.38 for gateway session for %s\n", chan->name); + return fp; +} - if (!details) { - ast_log(LOG_ERROR, "no FAX session details found on chan %s for T.38 gateway session, odd\n", chan->name); - ast_framehook_detach(chan, gateway->framehook); - return f; - } +static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *active, struct ast_frame *f) +{ + struct ast_frame *dfr = ast_frdup(f); + struct ast_dsp *active_dsp = (active == chan) ? gateway->chan_dsp : gateway->peer_dsp; + struct ast_channel *other = (active == chan) ? peer : chan; - t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters); - ao2_ref(details, -1); + if (gateway->detected_v21) { + return f; + } - if (!(dfr = ast_frisolate(&control_frame))) { - ast_log(LOG_ERROR, "error generating T.38 request control frame on chan %s for T.38 gateway session\n", chan->name); - return f; - } + if (!dfr) { + return f; + } - gateway->t38_state = T38_STATE_NEGOTIATING; - gateway->timeout_start = ast_tvnow(); + if (!(dfr = ast_dsp_process(active, active_dsp, dfr))) { + return f; + } - ast_debug(1, "detected CED tone on %s, requesting T.38 on %s for T.38 gateway session\n", active->name, other->name); - return dfr; + if (dfr->frametype == AST_FRAME_DTMF && dfr->subclass.integer == 'g') { + gateway->detected_v21 = 1; + if (ast_channel_get_t38_state(other) == T38_STATE_UNKNOWN) { + ast_debug(1, "detected v21 preamble from %s\n", active->name); + return fax_gateway_request_t38(gateway, chan, f); } else { - ast_debug(1, "detected CED tone on %s, but %s does not support T.38 for T.38 gateway session\n", active->name, other->name); + ast_debug(1, "detected v21 preamble on %s, but %s does not support T.38 for T.38 gateway session\n", active->name, other->name); } } @@ -2568,6 +2585,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str if (control_params->request_response == AST_T38_REQUEST_NEGOTIATE) { enum ast_t38_state state = ast_channel_get_t38_state(other); + if (state == T38_STATE_UNKNOWN) { /* we detected a request to negotiate T.38 and the * other channel appears to support T.38, we'll pass @@ -2607,7 +2625,7 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str return &ast_null_frame; } else if (gateway->t38_state == T38_STATE_NEGOTIATING) { /* we got a request to negotiate T.38 after we already - * sent one to the other party based on CED tone + * sent one to the other party based on v21 preamble * detection. We'll just pretend we passed this request * through in the first place. */ @@ -2615,12 +2633,12 @@ static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, str gateway->t38_state = T38_STATE_UNKNOWN; gateway->timeout_start = ast_tvnow(); - ast_debug(1, "%s is attempting to negotiate T.38 after we already sent a negotiation request based on CED detection\n", active->name); + ast_debug(1, "%s is attempting to negotiate T.38 after we already sent a negotiation request based on v21 preamble detection\n", active->name); ao2_ref(details, -1); return &ast_null_frame; } else if (gateway->t38_state == T38_STATE_NEGOTIATED) { /* we got a request to negotiate T.38 after we already - * sent one to the other party based on CED tone + * sent one to the other party based on v21 preamble * detection and received a response. We need to * respond to this and shut down the gateway. */ @@ -2841,7 +2859,8 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct gateway->timeout_start = ast_tvnow(); - /* we are bridged, change r/w formats to SLIN for CED detection and T.30 */ + /* we are bridged, change r/w formats to SLIN for v21 preamble + * detection and T.30 */ ast_format_copy(&gateway->chan_read_format, &chan->readformat); ast_format_copy(&gateway->chan_write_format, &chan->readformat); @@ -2916,16 +2935,16 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct return fax_gateway_detect_t38(gateway, chan, peer, active, f); } - /* not in gateway mode yet, listen for CED */ - /* XXX this should detect a v21 preamble instead of CED */ - if (gateway->t38_state == T38_STATE_UNAVAILABLE && f->frametype == AST_FRAME_VOICE) { - return fax_gateway_detect_ced(gateway, chan, peer, active, f); + if (!gateway->detected_v21 && gateway->t38_state == T38_STATE_UNAVAILABLE && f->frametype == AST_FRAME_VOICE) { + /* not in gateway mode and have not detected v21 yet, listen + * for v21 */ + return fax_gateway_detect_v21(gateway, chan, peer, active, f); } /* in gateway mode, gateway some packets */ if (gateway->t38_state == T38_STATE_NEGOTIATED) { /* framehooks are called in __ast_read() before frame format - * translation is does, so we need to translate here */ + * translation is done, so we need to translate here */ if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id != AST_FORMAT_SLINEAR)) { if (active->readtrans && (f = ast_translate(active->readtrans, f, 1)) == NULL) { f = &ast_null_frame; @@ -2942,6 +2961,25 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct return f; } + /* force silence on the line if T.38 negotiation might be taking place */ + if (gateway->t38_state != T38_STATE_UNAVAILABLE && gateway->t38_state != T38_STATE_REJECTED) { + if (f->frametype == AST_FRAME_VOICE && f->subclass.format.id == AST_FORMAT_SLINEAR) { + short silence_buf[f->samples]; + struct ast_frame silence_frame = { + .frametype = AST_FRAME_VOICE, + .data.ptr = silence_buf, + .samples = f->samples, + .datalen = sizeof(silence_buf), + }; + ast_format_set(&silence_frame.subclass.format, AST_FORMAT_SLINEAR, 0); + memset(silence_buf, 0, sizeof(silence_buf)); + + return ast_frisolate(&silence_frame); + } else { + return &ast_null_frame; + } + } + return f; } |