]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Delay sending an CED tone generated T.38 reinvite to give the CED tone
authorMatthew Nicholson <mnicholson@digium.com>
Mon, 11 Jul 2011 13:29:13 +0000 (13:29 +0000)
committerMatthew Nicholson <mnicholson@digium.com>
Mon, 11 Jul 2011 13:29:13 +0000 (13:29 +0000)
generating party time to send its own T.38 reinvite.

Also don't forward frames through the gateway if we are negotiating T.38.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@327511 65c4cc65-6c06-0410-ace0-fbb531ad65f3

res/res_fax.c

index 06b39e05c88ce2f2ec731741a766ac7bf2846a3e..5202e6323cfcfcc9e8019425ebaf0af4ccce878e 100644 (file)
@@ -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;
 }