diff options
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_dahdi.c | 43 | ||||
-rw-r--r-- | channels/chan_dahdi.h | 5 | ||||
-rw-r--r-- | channels/chan_pjsip.c | 53 | ||||
-rw-r--r-- | channels/chan_sip.c | 44 |
4 files changed, 104 insertions, 41 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index e4b7c0ee8..7a3c31fd5 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -1693,26 +1693,28 @@ static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub a if (strcmp(ast_channel_exten(ast), "fax")) { const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast)); - /* We need to unlock 'ast' here because ast_exists_extension has the + /* + * We need to unlock 'ast' here because ast_exists_extension has the * potential to start autoservice on the channel. Such action is prone - * to deadlock. + * to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding the + * channel lock. */ ast_mutex_unlock(&p->lock); ast_channel_unlock(ast); if (ast_exists_extension(ast, target_context, "fax", 1, S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast)); /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } else { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); } + ast_channel_lock(ast); + ast_mutex_lock(&p->lock); } else { ast_debug(1, "Already in a fax extension, not redirecting\n"); } @@ -2345,7 +2347,6 @@ static void my_pri_ss7_open_media(void *p) if (pvt->dsp_features && pvt->dsp) { ast_dsp_set_features(pvt->dsp, pvt->dsp_features); - pvt->dsp_features = 0; } } #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */ @@ -7200,26 +7201,28 @@ static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame if (strcmp(ast_channel_exten(ast), "fax")) { const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast)); - /* We need to unlock 'ast' here because ast_exists_extension has the + /* + * We need to unlock 'ast' here because ast_exists_extension has the * potential to start autoservice on the channel. Such action is prone - * to deadlock. + * to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding the + * channel lock. */ ast_mutex_unlock(&p->lock); ast_channel_unlock(ast); if (ast_exists_extension(ast, target_context, "fax", 1, S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast)); /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } else { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); } + ast_channel_lock(ast); + ast_mutex_lock(&p->lock); } else { ast_debug(1, "Already in a fax extension, not redirecting\n"); } @@ -8640,6 +8643,15 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast) /* Perform busy detection etc on the dahdi line */ int mute; + if ((p->dsp_features & DSP_FEATURE_FAX_DETECT) + && p->faxdetect_timeout + && p->faxdetect_timeout <= ast_channel_get_up_time(ast)) { + p->dsp_features &= ~DSP_FEATURE_FAX_DETECT; + ast_dsp_set_features(p->dsp, p->dsp_features); + ast_debug(1, "Channel driver fax CNG detection timeout on %s\n", + ast_channel_name(ast)); + } + f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f); /* Check if DSP code thinks we should be muting this frame and mute the conference if so */ @@ -12539,6 +12551,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, tmp->callprogress = conf->chan.callprogress; tmp->waitfordialtone = conf->chan.waitfordialtone; tmp->dialtone_detect = conf->chan.dialtone_detect; + tmp->faxdetect_timeout = conf->chan.faxdetect_timeout; tmp->cancallforward = conf->chan.cancallforward; tmp->dtmfrelax = conf->chan.dtmfrelax; tmp->callwaiting = tmp->permcallwaiting; @@ -17790,6 +17803,10 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct confp->chan.callprogress |= CALLPROGRESS_FAX_OUTGOING; } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING; + } else if (!strcasecmp(v->name, "faxdetect_timeout")) { + if (sscanf(v->value, "%30u", &confp->chan.faxdetect_timeout) != 1) { + confp->chan.faxdetect_timeout = 0; + } } else if (!strcasecmp(v->name, "echocancel")) { process_echocancel(confp, v->value, v->lineno); } else if (!strcasecmp(v->name, "echotraining")) { diff --git a/channels/chan_dahdi.h b/channels/chan_dahdi.h index 4bb5d19a2..ab5c1eba9 100644 --- a/channels/chan_dahdi.h +++ b/channels/chan_dahdi.h @@ -612,6 +612,11 @@ struct dahdi_pvt { */ int dialtone_detect; int dialtone_scanning_time_elapsed; /*!< Amount of audio scanned for dialtone, in frames */ + /*! + * \brief The number of seconds into call to disable fax detection. (0 = disabled) + * \note Set from the "faxdetect_timeout" value read in from chan_dahdi.conf + */ + unsigned int faxdetect_timeout; struct timeval waitingfordt; /*!< Time we started waiting for dialtone */ struct timeval flashtime; /*!< Last flash-hook time */ /*! \brief Opaque DSP configuration structure. */ diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 5ad117404..2e87393a6 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; @@ -628,16 +630,19 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se target_context = S_OR(ast_channel_macrocontext(session->channel), ast_channel_context(session->channel)); - /* We need to unlock the channel here because ast_exists_extension has the + /* + * We need to unlock the channel here because ast_exists_extension has the * potential to start and stop an autoservice on the channel. Such action * is prone to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding the channel lock. */ ast_channel_unlock(session->channel); + ast_frfree(f); + f = &ast_null_frame; exists = ast_exists_extension(session->channel, target_context, "fax", 1, S_COR(ast_channel_caller(session->channel)->id.number.valid, ast_channel_caller(session->channel)->id.number.str, NULL)); - ast_channel_lock(session->channel); - if (exists) { ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", ast_channel_name(session->channel)); @@ -646,12 +651,11 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se ast_log(LOG_ERROR, "Failed to async goto '%s' into fax extension in '%s'\n", ast_channel_name(session->channel), target_context); } - ast_frfree(f); - f = &ast_null_frame; } else { ast_log(LOG_NOTICE, "FAX CNG detected on '%s' but no fax extension in '%s'\n", ast_channel_name(session->channel), target_context); } + ast_channel_lock(session->channel); return f; } @@ -660,6 +664,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 +702,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/channels/chan_sip.c b/channels/chan_sip.c index 2149a9166..6913a039b 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -284,6 +284,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/features_config.h" #include "asterisk/http_websocket.h" #include "asterisk/format_cache.h" +#include "asterisk/linkedlists.h" /* for AST_LIST_NEXT */ /*** DOCUMENTATION <application name="SIPDtmfMode" language="en_US"> @@ -8609,29 +8610,31 @@ static struct ast_frame *sip_read(struct ast_channel *ast) if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) { if (strcmp(ast_channel_exten(ast), "fax")) { const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast)); - /* We need to unlock 'ast' here because + /* + * We need to unlock 'ast' here because * ast_exists_extension has the potential to start and * stop an autoservice on the channel. Such action is * prone to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding + * the channel lock. */ sip_pvt_unlock(p); ast_channel_unlock(ast); + ast_frfree(fr); + fr = &ast_null_frame; if (ast_exists_extension(ast, target_context, "fax", 1, S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) { - ast_channel_lock(ast); - sip_pvt_lock(p); ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", ast_channel_name(ast)); pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) { ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } - ast_frfree(fr); - fr = &ast_null_frame; } else { - ast_channel_lock(ast); - sip_pvt_lock(p); ast_log(LOG_NOTICE, "FAX CNG detected but no fax extension\n"); } + ast_channel_lock(ast); + sip_pvt_lock(p); } } @@ -13220,21 +13223,34 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext static char *crypto_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32) { + struct ast_sdp_srtp *tmp = srtp; char *a_crypto; - const char *orig_crypto; - if (!srtp || dtls_enabled) { + if (!tmp || dtls_enabled) { return NULL; } - orig_crypto = ast_sdp_srtp_get_attrib(srtp, dtls_enabled, default_taglen_32); - if (ast_strlen_zero(orig_crypto)) { + a_crypto = ast_strdup(""); + if (!a_crypto) { return NULL; } - if (ast_asprintf(&a_crypto, "a=crypto:%s\r\n", orig_crypto) == -1) { - return NULL; - } + do { + char *copy = a_crypto; + const char *orig_crypto = ast_sdp_srtp_get_attrib(tmp, dtls_enabled, default_taglen_32); + + if (ast_strlen_zero(orig_crypto)) { + ast_free(copy); + return NULL; + } + if (ast_asprintf(&a_crypto, "%sa=crypto:%s\r\n", copy, orig_crypto) == -1) { + ast_free(copy); + return NULL; + } + + ast_free(copy); + } while ((tmp = AST_LIST_NEXT(tmp, sdp_srtp_list))); + return a_crypto; } |