--- rtp.c.faxorig 2004-07-08 06:46:15.000000000 -0500 +++ rtp.c 2004-08-06 10:31:38.000000000 -0500 @@ -248,6 +248,8 @@ resp = '#'; } else if (event < 16) { resp = 'A' + (event - 12); + } else if (event == 36) { + resp = 'f'; // FAX } if (rtp->resp && (rtp->resp != resp)) { f = send_dtmf(rtp); --- channels/chan_sip.c.faxorig 2004-08-06 10:31:38.000000000 -0500 +++ channels/chan_sip.c 2004-08-09 11:17:46.000000000 -0500 @@ -198,6 +198,7 @@ static int videosupport = 0; static int global_dtmfmode = SIP_DTMF_RFC2833; /* DTMF mode default */ +static int global_faxmode = SIP_DTMF_RFC2833; /* FAX mode default */ static int recordhistory = 0; static int global_promiscredir; @@ -346,6 +347,7 @@ int progressinband; int dtmfmode; + int faxmode; struct ast_dsp *vad; struct sip_peer *peerpoke; /* If this calls is to poke a peer, which one */ @@ -396,6 +398,7 @@ int ospauth; /* Allow OSP Authentication */ #endif int dtmfmode; + int faxmode; int inUse; int incominglimit; int outUse; @@ -443,6 +446,7 @@ unsigned int pickupgroup; int promiscredir; int dtmfmode; + int faxmode; int trustrpid; int progressinband; struct sockaddr_in addr; @@ -1051,6 +1055,7 @@ u->capability = global_capability; u->nat = global_nat; u->dtmfmode = global_dtmfmode; + u->faxmode = global_faxmode; u->insecure = 1; u->temponly = 1; } @@ -1157,6 +1162,7 @@ p->capability = global_capability; p->nat = global_nat; p->dtmfmode = global_dtmfmode; + p->faxmode = global_faxmode; p->promiscredir = global_promiscredir; p->insecure = 1; p->expire = -1; @@ -1290,6 +1296,11 @@ else r->noncodeccapability &= ~AST_RTP_DTMF; } + if (p->faxmode) { + r->faxmode = p->faxmode; + if ((r->faxmode & SIP_DTMF_RFC2833) && !(r->dtmfmode & SIP_DTMF_RFC2833)) + ast_log(LOG_WARNING, "RFC2833 FAXMODE REQUIRES RFC2833 DTMFMODE"); + } r->promiscredir = p->promiscredir; strncpy(r->context, p->context,sizeof(r->context)-1); if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) && @@ -2004,6 +2015,15 @@ if (relaxdtmf) ast_dsp_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF); } + if (i->faxmode & SIP_DTMF_INBAND) { + if (i->dtmfmode & SIP_DTMF_INBAND) { + ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_DETECT); + } else { + i->vad = ast_dsp_new(); + /* DSP will not detect FAX if we do not ask it to detect DTMF too */ + ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_DETECT); + } + } tmp->fds[0] = ast_rtp_fd(i->rtp); tmp->fds[1] = ast_rtcp_fd(i->rtp); if (i->vrtp) { @@ -2203,10 +2223,13 @@ ast_set_read_format(p->owner, p->owner->readformat); ast_set_write_format(p->owner, p->owner->writeformat); } - if ((p->dtmfmode & SIP_DTMF_INBAND) && p->vad) { + if (((p->dtmfmode & SIP_DTMF_INBAND) || (p->faxmode & SIP_DTMF_INBAND)) && p->vad) { f = ast_dsp_process(p->owner,p->vad,f); - if (f && (f->frametype == AST_FRAME_DTMF)) + if (f && (f->frametype == AST_FRAME_DTMF)) { + if (!(p->dtmfmode & SIP_DTMF_INBAND) && (f->subclass != 'f')) + f = &null_frame; ast_log(LOG_DEBUG, "Detected DTMF '%c'\n", f->subclass); + } } } } @@ -2307,6 +2330,7 @@ /* Assign default music on hold class */ strncpy(p->musicclass, global_musicclass, sizeof(p->musicclass) - 1); p->dtmfmode = global_dtmfmode; + p->faxmode = global_faxmode; p->promiscredir = global_promiscredir; p->trustrpid = global_trustrpid; p->progressinband = global_progressinband; @@ -2318,6 +2342,8 @@ p->capability = global_capability; if (p->dtmfmode & SIP_DTMF_RFC2833) p->noncodeccapability |= AST_RTP_DTMF; + if ((p->faxmode & SIP_DTMF_RFC2833) && !(p->dtmfmode & SIP_DTMF_RFC2833)) + ast_log(LOG_WARNING, "RFC2833 FAXMODE REQUIRES RFC2833 DTMFMODE"); strncpy(p->context, default_context, sizeof(p->context) - 1); strncpy(p->fromdomain, default_fromdomain, sizeof(p->fromdomain) - 1); /* Add to list */ @@ -3421,8 +3447,13 @@ strncat(a, costr, sizeof(a) - strlen(a) - 1); if (x == AST_RTP_DTMF) { /* Indicate we support DTMF... Not sure about 16, but MSN supports it so dang it, we will too... */ - snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", - codec); + if (p->faxmode & SIP_DTMF_RFC2833) { + snprintf(costr, sizeof costr, "a=fmtp:%d 0-16,36\r\n", + codec); + } else { + snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", + codec); + } strncat(a, costr, sizeof(a) - strlen(a) - 1); } } @@ -5220,6 +5251,11 @@ else p->noncodeccapability &= ~AST_RTP_DTMF; } + if (user->faxmode) { + p->faxmode = user->faxmode; + if ((p->faxmode & SIP_DTMF_RFC2833) && !(p->dtmfmode & SIP_DTMF_RFC2833)) + ast_log(LOG_WARNING, "RFC2833 FAXMODE REQUIRES RFC2833 DTMFMODE"); + } } if (user && debug) ast_verbose("Found user '%s'\n", user->name); @@ -5301,6 +5337,11 @@ else p->noncodeccapability &= ~AST_RTP_DTMF; } + if (peer->faxmode) { + p->faxmode = peer->faxmode; + if ((p->faxmode & SIP_DTMF_RFC2833) && !(p->dtmfmode & SIP_DTMF_RFC2833)) + ast_log(LOG_WARNING, "RFC2833 FAXMODE REQUIRES RFC2833 DTMFMODE"); + } } if (peer->temponly) { if (peer->ha) { @@ -5577,6 +5618,12 @@ if (peer->dtmfmode == SIP_DTMF_INBAND) ast_cli(fd, "inband "); ast_cli(fd, "\n" ); + ast_cli(fd, " Faxmode : "); + if (peer->faxmode == SIP_DTMF_RFC2833) + ast_cli(fd, "rfc2833 "); + if (peer->faxmode == SIP_DTMF_INBAND) + ast_cli(fd, "inband "); + ast_cli(fd, "\n" ); ast_cli(fd, " LastMsg : %d\n", peer->lastmsg); ast_cli(fd, " ToHost : %s\n", peer->tohost); ast_cli(fd, " Addr->IP : %s Port %d\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)", ntohs(peer->addr.sin_port)); @@ -5788,7 +5835,12 @@ strncat(tmp, "info ", sizeof(tmp) - strlen(tmp) - 1); if (cur->dtmfmode & SIP_DTMF_INBAND) strncat(tmp, "inband ", sizeof(tmp) - strlen(tmp) - 1); - ast_cli(fd, " DTMF Mode: %s\n\n", tmp); + ast_cli(fd, " DTMF Mode: %s\n", tmp); + if (cur->faxmode & SIP_DTMF_RFC2833) + strncat(tmp, "rfc2833 ", sizeof(tmp) - strlen(tmp) - 1); + if (cur->faxmode & SIP_DTMF_INBAND) + strncat(tmp, "inband ", sizeof(tmp) - strlen(tmp) - 1); + ast_cli(fd, " FAX Mode: %s\n\n", tmp); found++; } cur = cur->next; @@ -7871,6 +7923,15 @@ ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value); user->dtmfmode = SIP_DTMF_RFC2833; } + } else if (!strcasecmp(v->name, "faxmode")) { + if (!strcasecmp(v->value, "inband")) + user->faxmode=SIP_DTMF_INBAND; + else if (!strcasecmp(v->value, "rfc2833")) + user->faxmode = SIP_DTMF_RFC2833; + else { + ast_log(LOG_WARNING, "Unknown fax mode '%s', using rfc2833\n", v->value); + user->faxmode = SIP_DTMF_RFC2833; + } } else if (!strcasecmp(v->name, "canreinvite")) { if (!strcasecmp(v->value, "update")) user->canreinvite = REINVITE_UPDATE; @@ -7971,6 +8032,7 @@ /* Assume can reinvite */ peer->canreinvite = global_canreinvite; peer->dtmfmode = global_dtmfmode; + peer->faxmode = global_faxmode; peer->promiscredir = global_promiscredir; peer->nat = global_nat; peer->rtptimeout = global_rtptimeout; @@ -8041,6 +8103,7 @@ peer->rtptimeout = global_rtptimeout; peer->rtpholdtimeout = global_rtpholdtimeout; peer->dtmfmode = 0; + peer->faxmode = 0; peer->promiscredir = global_promiscredir; peer->trustrpid = global_trustrpid; peer->progressinband = global_progressinband; @@ -8083,6 +8146,15 @@ ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value); peer->dtmfmode = SIP_DTMF_RFC2833; } + } else if (!strcasecmp(v->name, "faxmode")) { + if (!strcasecmp(v->value, "inband")) + peer->faxmode=SIP_DTMF_INBAND; + else if (!strcasecmp(v->value, "rfc2833")) + peer->faxmode = SIP_DTMF_RFC2833; + else { + ast_log(LOG_WARNING, "Unknown fax mode '%s', using rfc2833\n", v->value); + peer->faxmode = SIP_DTMF_RFC2833; + } } else if (!strcasecmp(v->name, "host")) { if (!strcasecmp(v->value, "dynamic")) { /* They'll register with us */ @@ -8221,6 +8293,7 @@ char iabuf[INET_ADDRSTRLEN]; global_dtmfmode = SIP_DTMF_RFC2833; + global_faxmode = SIP_DTMF_RFC2833; global_promiscredir = 0; if (gethostname(ourhost, sizeof(ourhost))) { @@ -8282,6 +8355,15 @@ ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value); global_dtmfmode = SIP_DTMF_RFC2833; } + } else if (!strcasecmp(v->name, "faxmode")) { + if (!strcasecmp(v->value, "inband")) + global_faxmode=SIP_DTMF_INBAND; + else if (!strcasecmp(v->value, "rfc2833")) + global_faxmode = SIP_DTMF_RFC2833; + else { + ast_log(LOG_WARNING, "Unknown fax mode '%s', using rfc2833\n", v->value); + global_faxmode = SIP_DTMF_RFC2833; + } } else if (!strcasecmp(v->name, "rtptimeout")) { if ((sscanf(v->value, "%d", &global_rtptimeout) != 1) || (global_rtptimeout < 0)) { ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d. Using default.\n", v->value, v->lineno); @@ -8598,13 +8680,66 @@ p->dtmfmode = SIP_DTMF_INBAND; else ast_log(LOG_WARNING, "I don't know about this dtmf mode: %s\n",mode); - if (p->dtmfmode & SIP_DTMF_INBAND) { - if (!p->vad) { - p->vad = ast_dsp_new(); - ast_dsp_set_features(p->vad, DSP_FEATURE_DTMF_DETECT); - } - } else { - if (p->vad) { + if (p->dtmfmode & SIP_DTMF_INBAND) { + if (!p->vad) p->vad = ast_dsp_new(); + if (p->faxmode & SIP_DTMF_INBAND) { + ast_dsp_set_features(p->vad, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_DETECT); + } else { + ast_dsp_set_features(p->vad, DSP_FEATURE_DTMF_DETECT); + } + } else { + if ((p->faxmode & SIP_DTMF_INBAND) && p->vad) { + /* DSP will not detect FAX if we do not ask it to detect DTMF too */ + ast_dsp_set_features(p->vad, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_DETECT); + } else { + ast_dsp_free(p->vad); + p->vad = NULL; + } + } + ast_mutex_unlock(&p->lock); + } + ast_mutex_unlock(&chan->lock); + return 0; +} + +static char *synopsis_faxmode = "Change the faxmode for a SIP call"; +static char *descrip_faxmode = "SIPFaxMode(inband|rfc2833): Changes the faxmode for a SIP call\n"; +static char *app_faxmode = "SIPFaxMode"; + +/*--- sip_faxmode: change the Faxmode for a SIP call (application) ---*/ +static int sip_faxmode(struct ast_channel *chan, void *data) +{ + struct sip_pvt *p; + char *mode; + if (data) + mode = (char *)data; + else { + ast_log(LOG_WARNING, "This application requires the argument: info, rfc2833\n"); + return 0; + } + ast_mutex_lock(&chan->lock); + if (chan->type != type) { + ast_log(LOG_WARNING, "Call this application only on SIP incoming calls\n"); + ast_mutex_unlock(&chan->lock); + return 0; + } + p = chan->pvt->pvt; + if (p) { + ast_mutex_lock(&p->lock); + if (!strcasecmp(mode,"rfc2833")) + p->faxmode = SIP_DTMF_RFC2833; + else if (!strcasecmp(mode,"inband")) + p->faxmode = SIP_DTMF_INBAND; + else + ast_log(LOG_WARNING, "I don't know about this fax mode: %s\n",mode); + if (p->faxmode & SIP_DTMF_INBAND) { + if (!p->vad) p->vad = ast_dsp_new(); + /* DSP will not detect FAX if we do not ask it to detect DTMF too */ + ast_dsp_set_features(p->vad, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_DETECT); + } else { + if ((p->dtmfmode & SIP_DTMF_INBAND) && p->vad) { + ast_dsp_set_features(p->vad, DSP_FEATURE_DTMF_DETECT); + } else { ast_dsp_free(p->vad); p->vad = NULL; } @@ -8797,6 +8932,7 @@ sip_rtp.type = type; ast_rtp_proto_register(&sip_rtp); ast_register_application(app_dtmfmode, sip_dtmfmode, synopsis_dtmfmode, descrip_dtmfmode); + ast_register_application(app_faxmode, sip_faxmode, synopsis_faxmode, descrip_faxmode); ast_mutex_lock(&peerl.lock); for (peer = peerl.peers; peer; peer = peer->next) sip_poke_peer(peer); @@ -8819,6 +8955,7 @@ /* First, take us out of the channel loop */ ast_unregister_application(app_dtmfmode); + ast_unregister_application(app_faxmode); ast_cli_unregister(&cli_show_users); ast_cli_unregister(&cli_show_channels); ast_cli_unregister(&cli_show_channel);