1/27/19: Update: Elastic SIP trunks now support CNAM. This method outlined below is still useful for passing caller name with programmable voice.
A couple months ago I switched my Dad’s business over to Twilio Elastic SIP trunks. I have been very happy with the service. Not only was it really easy to deploy, but the service has been rock solid. The only downside that I discovered during my initial testing was that Twilio doesn’t deliver the caller name in the SIP header! Twilio offers a service for lookups and there are a couple add-ons that will do caller name lookups, however, they don’t alter the SIP headers. In the solution below, I am using the addOn OpenCNAM by telo. This will work with Twilio’s lookup service, but the function will need to be altered to capture the correct data. I found OpenCNAM to be more accurate. It took me a bit of trial and error, but I finally figured out a solution! In order to make this work, follow the steps below.
example-function.js
exports.handler = function (context, event, callback) {
if (event.AddOns) {
fromName = getName(event.AddOns);
} else {
fromName = event.From; // send the original calling number if no AddOns are found
}
let twiml = new Twilio.twiml.VoiceResponse();
let dial = twiml.dial();
dial.sip("sip:[email protected]?fromName=" + fromName); // replace with a URI directed at CUBE
callback(null, twiml);
};
var getName = function (input) {
var addOn = JSON.parse(input);
//var callerName = JSON.parse();
if (addOn.results.opencnam.result.name) {
var name = addOn.results.opencnam.result.name;
// remove spaces, Twilio doesn't allow spaces to be passed in the custom headers
name = name.replace(/\s/g, "_");
// limit to 15 characters
name = name.substring(0, 15);
console.log("returning name: ", name);
return name;
} else {
// if a name isn't found, the number will be returned
console.log("returning number: ", addOn.results.opencnam.result.number);
return addOn.results.opencnam.result.number;
}
};
CUBE:
A handful of things need to be done on CUBE. First a sip-copylist and sip-profile will need to be created.
sip-copylist
voice class sip-copylist 1
voice class sip-copylist 1
sip-header X-fromName
sip-profiles voice class sip-profiles 1
voice class sip-profiles 1
request INVITE peer-header sip X-fromName copy "(.*)" u01
request INVITE sip-header P-Asserted-Identity modify ".*(<.*)" "P-Asserted-Identity: \"\u01\" \1"
Once the copylist and profile have been created, they will be applied to an inbound and outbound dial-peer.
dial-peer example
dial-peer voice 1 voip
description ** SP to CUBE catchall **
session protocol sipv2
incoming called-number .
voice-class sip copy-list 1
voice-class sip bind control source-interface FastEthernet0/0
voice-class sip bind media source-interface FastEthernet0/0
dtmf-relay rtp-nte sip-kpml sip-notify
codec g711ulaw
no vad
dial-peer voice 1000 voip
description ** CUBE to CUCM **
destination-pattern 1000
session protocol sipv2
session target ipv4:<CUCM IP Address>
voice-class sip profiles 1
voice-class sip options-keepalive down-interval 10
voice-class sip bind control source-interface GigabitEthernet1/0.10
voice-class sip bind media source-interface GigabitEthernet1/0.10
dtmf-relay rtp-nte
codec g711ulaw
no vad
The final step is to point the phone number at the Twilio Function. You should now see caller name on inbound calls!
Hopefully this will save some time for the next person trying to figure this out!
Enjoy,
– Brad