Compare commits

...
2 Commits
Author SHA1 Message Date
Hoan Luu Huu b8a67019a1 support sending DTMF to caller (#125)
* support sending DTMF to caller

* wip
2023-12-13 09:14:27 -05:00
Hoan Luu Huu 0e1627ba82 phone number's application should override voice carrier default application (#128)
* phone number's application should override voice carrier default application

* fix review comments

* fix review comments
2023-12-13 08:25:26 -05:00
3 changed files with 40 additions and 6 deletions
+21
View File
@@ -780,6 +780,27 @@ Duration=${payload.duration} `
)).every((r) => r);
}
res.send(succeeded ? 200 : 503);
} else if (reason.includes('Dtmf')) {
const arr = /Signal=\s*([0-9#*])/.exec(req.body);
if (!arr) {
this.logger.info({body: req.body}, '_onInfo: invalid INFO Dtmf');
throw new Error(`_onInfo: no dtmf in body for ${contentType}`);
}
const code = arr[1];
const arr2 = /Duration=\s*(\d+)/.exec(req.body);
const duration = arr2 ? arr2[1] : 250;
const dtmfOpts = {
...this.rtpEngineOpts.common,
'from-tag': this.rtpEngineOpts.uac.tag,
code,
duration
};
const response = await this.playDTMF(dtmfOpts);
if ('ok' !== response.result) {
this.logger.info({response}, `rtpengine play Dtmf failed with ${JSON.stringify(response)}`);
throw new Error('rtpengine failed: answer');
}
res.send(200);
}
}
else if (dlg.type === 'uas' && ['application/dtmf-relay', 'application/dtmf'].includes(contentType)) {
+17 -4
View File
@@ -142,7 +142,7 @@ module.exports = (srf, logger) => {
const failure = {fromCarrier: false};
const uri = parseUri(req.uri);
const isDotDecimal = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/.test(uri.host);
const did = normalizeDID(req.calledNumber) || 'anonymous';
if (!isDotDecimal) {
/**
* The host part of the SIP URI is not a dot-decimal IP address,
@@ -175,12 +175,19 @@ module.exports = (srf, logger) => {
.sort((a, b) => b.netmask - a.netmask);
const selected = gw.find(gatewayMatchesSourceAddress.bind(null, logger, req.source_address));
if (selected) {
const sql =
`SELECT application_sid FROM phone_numbers WHERE number = '${did}'
AND voip_carrier_sid = '${selected.voip_carrier_sid}'
AND account_sid = '${a[0].account_sid}'`;
logger.debug({selected, sql, did}, 'looking up DID');
const [r] = await pp.query(sql);
return {
fromCarrier: true,
gateway: selected,
service_provider_sid: a[0].service_provider_sid,
account_sid: a[0].account_sid,
application_sid: selected.application_sid,
application_sid: r[0]?.application_sid || selected.application_sid,
account: a[0]
};
}
@@ -207,12 +214,19 @@ module.exports = (srf, logger) => {
const [a] = await pp.query(sqlAccountBySid, [[matches[0].account_sid]]);
if (0 === a.length) return failure;
logger.debug({matches}, `found registration carrier using ${uri.host} and ${uri.user}`);
const sql =
`SELECT application_sid FROM phone_numbers WHERE number = '${did}'
AND voip_carrier_sid = '${matches[0].voip_carrier_sid}'
AND account_sid = '${matches[0].account_sid}'`;
logger.debug({matches: matches[0], sql, did}, 'looking up DID');
const [r] = await pp.query(sql);
return {
fromCarrier: true,
gateway: matches[0],
service_provider_sid: a[0].service_provider_sid,
account_sid: a[0].account_sid,
application_sid: matches[0].application_sid,
application_sid: r[0]?.application_sid || matches[0].application_sid,
account: a[0]
};
}
@@ -264,7 +278,6 @@ module.exports = (srf, logger) => {
if (matches.length) {
/* we have one or more matches. Now check for one with a provisioned phone number matching the DID */
const vc_sids = matches.map((m) => `'${m.voip_carrier_sid}'`).join(',');
const did = normalizeDID(req.calledNumber) || 'anonymous';
const sql = `SELECT * FROM phone_numbers WHERE number = '${did}' AND voip_carrier_sid IN (${vc_sids})`;
logger.debug({matches, sql, did, vc_sids}, 'looking up DID');
+2 -2
View File
@@ -22,8 +22,8 @@ function makeRtpEngineOpts(req, srcIsUsingSrtp, dstIsUsingSrtp, teams = false) {
const dstOpts = dstIsUsingSrtp ? srtpOpts : rtpCopy;
const srcOpts = srcIsUsingSrtp ? srtpOpts : rtpCopy;
/* webrtc clients (e.g. sipjs) send DMTF via SIP INFO */
if ((srcIsUsingSrtp || dstIsUsingSrtp) && !teams) {
/* Allow Feature server to inject DTMF to both leg except call from Teams*/
if (!teams) {
dstOpts.flags.push('inject DTMF');
srcOpts.flags.push('inject DTMF');
}