diff options
Diffstat (limited to 'res')
-rw-r--r-- | res/res_fax.c | 105 |
1 files changed, 72 insertions, 33 deletions
diff --git a/res/res_fax.c b/res/res_fax.c index 06b39e05c..5202e6323 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -246,6 +246,8 @@ struct fax_gateway { struct ast_fax_tech_token *token; /*! \brief the start of our timeout counter */ struct timeval timeout_start; + /*! \brief the start of our ced timeout */ + struct timeval ced_timeout_start; /*! \brief DSP Processor */ struct ast_dsp *chan_dsp; struct ast_dsp *peer_dsp; @@ -253,6 +255,8 @@ struct fax_gateway { int framehook; /*! \brief bridged */ int bridged:1; + /*! \brief 1 if the ced tone came from chan, 0 if it came from peer */ + int ced_chan:1; /*! \brief a flag to track the state of our negotiation */ enum ast_t38_state t38_state; /*! \brief original audio formats */ @@ -269,6 +273,7 @@ static int fax_logger_level = -1; #define RES_FAX_TIMEOUT 10000 #define FAX_GATEWAY_TIMEOUT RES_FAX_TIMEOUT +#define FAX_GATEWAY_CED_TIMEOUT 3000 /*! \brief The faxregistry is used to manage information and statistics for all FAX sessions. */ static struct { @@ -2465,6 +2470,46 @@ static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session return 0; } +static struct ast_frame *fax_gateway_send_ced(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_frame *f) +{ + 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, + }; + + 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; + } + + 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; + } + + gateway->t38_state = T38_STATE_NEGOTIATING; + gateway->timeout_start = ast_tvnow(); + + gateway->ced_timeout_start.tv_sec = 0; + gateway->ced_timeout_start.tv_usec = 0; + + ast_debug(1, "detected CED tone; requesting T.38 for gateway session for %s\n", chan->name); + return fp; +} + 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) { struct ast_frame *dfr = ast_frdup(f); @@ -2480,40 +2525,13 @@ static struct ast_frame *fax_gateway_detect_ced(struct fax_gateway *gateway, str } 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, - }; - - struct ast_fax_session_details *details = find_details(chan); - ast_frfree(dfr); - - 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; - } - - t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters); - ao2_ref(details, -1); - - 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 (ast_channel_get_t38_state(other) == T38_STATE_UNKNOWN && ast_tvzero(gateway->ced_timeout_start)) { + if (ast_channel_get_t38_state(active) == T38_STATE_UNKNOWN) { + gateway->ced_timeout_start = ast_tvnow(); + gateway->ced_chan = (active == chan); + } else { + return fax_gateway_send_ced(gateway, chan, f); } - - gateway->t38_state = T38_STATE_NEGOTIATING; - gateway->timeout_start = ast_tvnow(); - - 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; } 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); } @@ -2568,6 +2586,10 @@ 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); + + gateway->ced_timeout_start.tv_sec = 0; + gateway->ced_timeout_start.tv_usec = 0; + 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 @@ -2922,6 +2944,17 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct return fax_gateway_detect_ced(gateway, chan, peer, active, f); } + /* handle the ced timeout delay */ + if (!ast_tvzero(gateway->ced_timeout_start)) { + if (ast_tvdiff_ms(ast_tvnow(), gateway->ced_timeout_start) > FAX_GATEWAY_CED_TIMEOUT) { + if (gateway->ced_chan && chan == active) { + return fax_gateway_send_ced(gateway, chan, f); + } else if (!gateway->ced_chan && peer == active) { + return fax_gateway_send_ced(gateway, chan, f); + } + } + } + /* in gateway mode, gateway some packets */ if (gateway->t38_state == T38_STATE_NEGOTIATED) { /* framehooks are called in __ast_read() before frame format @@ -2942,6 +2975,12 @@ 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 (!ast_tvzero(gateway->ced_timeout_start) || (gateway->t38_state != T38_STATE_UNAVAILABLE && gateway->t38_state != T38_STATE_REJECTED)) { + /* XXX may need to return a silence frame here */ + return &ast_null_frame; + } + return f; } |