diff --git a/channels/chan_sip.c b/channels/chan_sip.c index f36f05036d1ae8829a8785b85448e3452f9aa742..bb5e4956724f8fdbc76bc495d8117cf526707dd3 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1828,7 +1828,7 @@ struct sip_pvt { int laststate; /*!< SUBSCRIBE: Last known extension state */ int dialogver; /*!< SUBSCRIBE: Version for subscription dialog-info */ - struct ast_dsp *dsp; /*!< Inband DTMF Detection dsp */ + struct ast_dsp *dsp; /*!< Inband DTMF or Fax CNG tone Detection dsp */ struct sip_peer *relatedpeer; /*!< If this dialog is related to a peer, which one Used in peerpoke, mwi subscriptions */ @@ -4442,23 +4442,40 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittyp return res; } -static void enable_digit_detect(struct sip_pvt *p) +static void enable_dsp_detect(struct sip_pvt *p) { + int features = 0; + if (p->dsp) { return; } + if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) || + (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) { + if (!p->rtp || ast_rtp_instance_dtmf_mode_set(p->rtp, AST_RTP_DTMF_MODE_INBAND)) { + features |= DSP_FEATURE_DIGIT_DETECT; + } + } + + if (ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT)) { + features |= DSP_FEATURE_FAX_DETECT; + } + + if (!features) { + return; + } + if (!(p->dsp = ast_dsp_new())) { return; } - ast_dsp_set_features(p->dsp, DSP_FEATURE_DIGIT_DETECT); + ast_dsp_set_features(p->dsp, features); if (global_relaxdtmf) { ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF); } } -static void disable_digit_detect(struct sip_pvt *p) +static void disable_dsp_detect(struct sip_pvt *p) { if (p->dsp) { ast_dsp_free(p->dsp); @@ -4489,9 +4506,9 @@ static int sip_setoption(struct ast_channel *chan, int option, void *data, int d ast_debug(1, "%sabling digit detection on %s\n", *cp ? "En" : "Dis", chan->name); if (*cp) { - enable_digit_detect(p); + enable_dsp_detect(p); } else { - disable_digit_detect(p); + disable_dsp_detect(p); } res = 0; } @@ -6329,7 +6346,7 @@ static int sip_hangup(struct ast_channel *ast) append_history(p, needcancel ? "Cancel" : "Hangup", "Cause %s", p->owner ? ast_cause2str(p->hangupcause) : "Unknown"); /* Disconnect */ - disable_digit_detect(p); + disable_dsp_detect(p); p->owner = NULL; ast->tech_pvt = dialog_unref(ast->tech_pvt, "unref ast->tech_pvt"); @@ -6996,10 +7013,12 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit else ast_debug(3, "This channel will not be able to handle video.\n"); + enable_dsp_detect(i); + if ((ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) || (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) { if (!i->rtp || ast_rtp_instance_dtmf_mode_set(i->rtp, AST_RTP_DTMF_MODE_INBAND)) { - enable_digit_detect(i); + enable_dsp_detect(i); } } else if (ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) { if (i->rtp) { @@ -7321,9 +7340,17 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p if (f && p->dsp) { f = ast_dsp_process(p->owner, p->dsp, f); if (f && f->frametype == AST_FRAME_DTMF) { - if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && f->subclass.integer == 'f') { - ast_debug(1, "Fax CNG detected on %s\n", ast->name); + if (f->subclass.integer == 'f') { + if (option_debug) + ast_log(LOG_DEBUG, "Fax CNG detected on %s\n", ast->name); *faxdetect = 1; + /* If we only needed this DSP for fax detection purposes we can just drop it now */ + if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) { + ast_dsp_set_features(p->dsp, DSP_FEATURE_DIGIT_DETECT); + } else { + ast_dsp_free(p->dsp); + p->dsp = NULL; + } } else { ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.integer); } @@ -7344,20 +7371,26 @@ static struct ast_frame *sip_read(struct ast_channel *ast) fr = sip_rtp_read(ast, p, &faxdetected); p->lastrtprx = time(NULL); - /* If we are NOT bridged to another channel, and we have detected fax tone we issue T38 re-invite to a peer */ - /* If we are bridged then it is the responsibility of the SIP device to issue T38 re-invite if it detects CNG or fax preamble */ - if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) { - if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) { - if (!p->pendinginvite) { - ast_debug(3, "Sending reinvite on SIP (%s) for T.38 negotiation.\n", ast->name); - change_t38_state(p, T38_LOCAL_REINVITE); - transmit_reinvite_with_sdp(p, TRUE, FALSE); - } - } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) { - ast_debug(3, "Deferring reinvite on SIP (%s) - it will be re-negotiated for T.38\n", ast->name); - ast_set_flag(&p->flags[0], SIP_NEEDREINVITE); - } - } + /* If we detect a CNG tone and fax detection is enabled then send us off to the fax extension */ + if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT)) { + ast_channel_lock(ast); + if (strcmp(ast->exten, "fax")) { + const char *target_context = S_OR(ast->macrocontext, ast->context); + ast_channel_unlock(ast); + if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) { + ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension\n", ast->name); + pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten); + if (ast_async_goto(ast, target_context, "fax", 1)) { + ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context); + } + fr = &ast_null_frame; + } else { + ast_log(LOG_NOTICE, "Fax detected but no fax extension\n"); + } + } else { + ast_channel_unlock(ast); + } + } /* Only allow audio through if they sent progress with SDP, or if the channel is actually answered */ if (fr && fr->frametype == AST_FRAME_VOICE && p->invitestate != INV_EARLY_MEDIA && ast->_state != AST_STATE_UP) { @@ -26521,9 +26554,9 @@ static int sip_dtmfmode(struct ast_channel *chan, const char *data) ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833); if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) || (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) { - enable_digit_detect(p); + enable_dsp_detect(p); } else { - disable_digit_detect(p); + disable_dsp_detect(p); } sip_pvt_unlock(p); ast_channel_unlock(chan); diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample index c42f9abf7051bedbb7d25bce0b1631c033ee84eb..af3012a7a750d2be266dcb569c9259f282970ca2 100644 --- a/configs/sip.conf.sample +++ b/configs/sip.conf.sample @@ -552,7 +552,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; ; send 400 byte T.38 FAX packets to it. ; ; FAX detection will cause the SIP channel to jump to the 'fax' extension (if it exists) -; after T.38 is successfully negotiated. +; when a CNG tone is detected on an incoming call. ; ; faxdetect = yes ; Default false ;