diff --git a/CHANGES b/CHANGES index 9caa524226..62d81783ba 100644 --- a/CHANGES +++ b/CHANGES @@ -366,6 +366,10 @@ cdr_csv res_pjsip ------------------ + * Added "fax_detect_timeout" to endpoint. + The option determines how many seconds into a call before fax_detect + is disabled for the call. Setting the value to zero disables the timeout. + * Added "subscribe_context" to endpoint. If specified, incoming SUBSCRIBE requests will be searched for the matching extension in the indicated context. If no "subscribe_context" is specified, diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 5ad1174047..5a341f866f 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -612,10 +612,12 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se { const char *target_context; int exists; + int dsp_features; - /* If we only needed this DSP for fax detection purposes we can just drop it now */ - if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) { - ast_dsp_set_features(session->dsp, DSP_FEATURE_DIGIT_DETECT); + dsp_features = ast_dsp_get_features(session->dsp); + dsp_features &= ~DSP_FEATURE_FAX_DETECT; + if (dsp_features) { + ast_dsp_set_features(session->dsp, dsp_features); } else { ast_dsp_free(session->dsp); session->dsp = NULL; @@ -660,6 +662,7 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); + struct ast_sip_session *session; struct chan_pjsip_pvt *pvt = channel->pvt; struct ast_frame *f; struct ast_sip_session_media *media = NULL; @@ -697,22 +700,42 @@ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) return f; } - if (ast_format_cap_iscompatible_format(channel->session->endpoint->media.codecs, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + session = channel->session; + + if (ast_format_cap_iscompatible_format(session->endpoint->media.codecs, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when endpoint '%s' is not configured for it\n", ast_format_get_name(f->subclass.format), ast_channel_name(ast), - ast_sorcery_object_get_id(channel->session->endpoint)); + ast_sorcery_object_get_id(session->endpoint)); ast_frfree(f); return &ast_null_frame; } - if (channel->session->dsp) { - f = ast_dsp_process(ast, channel->session->dsp, f); + if (session->dsp) { + int dsp_features; + dsp_features = ast_dsp_get_features(session->dsp); + if ((dsp_features & DSP_FEATURE_FAX_DETECT) + && session->endpoint->faxdetect_timeout + && session->endpoint->faxdetect_timeout <= ast_channel_get_up_time(ast)) { + dsp_features &= ~DSP_FEATURE_FAX_DETECT; + if (dsp_features) { + ast_dsp_set_features(session->dsp, dsp_features); + } else { + ast_dsp_free(session->dsp); + session->dsp = NULL; + } + ast_debug(3, "Channel driver fax CNG detection timeout on %s\n", + ast_channel_name(ast)); + } + } + if (session->dsp) { + f = ast_dsp_process(ast, session->dsp, f); if (f && (f->frametype == AST_FRAME_DTMF)) { if (f->subclass.integer == 'f') { - ast_debug(3, "Fax CNG detected on %s\n", ast_channel_name(ast)); - f = chan_pjsip_cng_tone_detected(channel->session, f); + ast_debug(3, "Channel driver fax CNG detected on %s\n", + ast_channel_name(ast)); + f = chan_pjsip_cng_tone_detected(session, f); } else { ast_debug(3, "* Detected inband DTMF '%c' on '%s'\n", f->subclass.integer, ast_channel_name(ast)); diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 9069a669f7..4c42e8a5fa 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -693,6 +693,10 @@ ;t38_udptl_maxdatagram=0 ; T 38 UDPTL maximum datagram size (default: ; "0") ;fax_detect=no ; Whether CNG tone detection is enabled (default: "no") +;fax_detect_timeout=30 ; How many seconds into a call before fax_detect is + ; disabled for the call. + ; Zero disables the timeout. + ; (default: "0") ;t38_udptl_nat=no ; Whether NAT support is enabled on UDPTL sessions ; (default: "no") ;t38_udptl_ipv6=no ; Whether IPv6 is used for UDPTL Sessions (default: diff --git a/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py b/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py new file mode 100644 index 0000000000..91774c447c --- /dev/null +++ b/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py @@ -0,0 +1,23 @@ +"""add fax_detect_timeout option + +Revision ID: 4a6c67fa9b7a +Revises: 9deac0ae4717 +Create Date: 2016-07-18 18:20:44.249491 + +""" + +# revision identifiers, used by Alembic. +revision = '4a6c67fa9b7a' +down_revision = '9deac0ae4717' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_endpoints', sa.Column('fax_detect_timeout', sa.Integer)) + + +def downgrade(): + op.drop_column('ps_endpoints', 'fax_detect_timeout') + diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 6f59283651..9dd70dbcaa 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -753,6 +753,8 @@ struct ast_sip_endpoint { struct ast_acl_list *acl; /* Restrict what IPs are allowed in the Contact header (for registration) */ struct ast_acl_list *contact_acl; + /*! The number of seconds into call to disable fax detection. (0 = disabled) */ + unsigned int faxdetect_timeout; }; /*! diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 5ca2c99a52..26dd451a79 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -139,7 +139,7 @@ struct ast_sip_session { struct ast_party_id id; /*! Requested capabilities */ struct ast_format_cap *req_caps; - /*! Optional DSP, used only for inband DTMF detection if configured */ + /*! Optional DSP, used only for inband DTMF/Fax-CNG detection if configured */ struct ast_dsp *dsp; /*! Whether the termination of the session should be deferred */ unsigned int defer_terminate:1; diff --git a/main/channel.c b/main/channel.c index f654e4d257..911c269558 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2692,10 +2692,28 @@ void ast_hangup(struct ast_channel *chan) ast_channel_unref(chan); } +/*! + * \internal + * \brief Set channel answered time if not already set. + * \since 13.11.0 + * + * \param chan Channel to set answered time. + * + * \return Nothing + */ +static void set_channel_answer_time(struct ast_channel *chan) +{ + if (ast_tvzero(ast_channel_answertime(chan))) { + struct timeval answertime; + + answertime = ast_tvnow(); + ast_channel_answertime_set(chan, &answertime); + } +} + int ast_raw_answer(struct ast_channel *chan) { int res = 0; - struct timeval answertime; ast_channel_lock(chan); @@ -2711,8 +2729,11 @@ int ast_raw_answer(struct ast_channel *chan) return -1; } - answertime = ast_tvnow(); - ast_channel_answertime_set(chan, &answertime); + /* + * Mark when incoming channel answered so we can know how + * long the channel has been up. + */ + set_channel_answer_time(chan); ast_channel_unlock(chan); @@ -3911,6 +3932,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) ast_frfree(f); f = &ast_null_frame; } else { + /* + * Mark when outgoing channel answered so we can know how + * long the channel has been up. + */ + set_channel_answer_time(chan); + ast_setstate(chan, AST_STATE_UP); } } else if (f->subclass.integer == AST_CONTROL_READ_ACTION) { diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 882f57876f..a1deb9e5fc 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -600,6 +600,14 @@ detected. + + How long into a call before fax_detect is disabled for the call + + The option determines how many seconds into a call before the + fax_detect option is disabled for the call. Setting the value + to zero disables the timeout. + + Whether NAT support is enabled on UDPTL sessions diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index d399f0b47f..16405ebce7 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1849,6 +1849,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, t38udptl_ec_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_maxdatagram", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.t38.maxdatagram)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, faxdetect)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect_timeout", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, faxdetect_timeout)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.nat)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.ipv6)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tone_zone", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, zone));