I'm trying to make automated calls to my customers, I already have my freepbx setup and working, now I want to be able to fire some nodejs code to make the call, get the audio stream and pass it to dialogflow and play an MP3 (or any other audio type) to the customer based on the dialogflow response.
I've tried with this package:
https://github.com/versatica/JsSIP
And I can establish the call and get the audio stream. Yup, that's great, if only wasn't in a html on the browser... But then I found this!
https://github.com/versatica/jssip-node-websocket
Looked like the answer to all my questions until I tried to place a call from my nodejs script, surprise, doesn't work, and is not even intended to work, it's just for sending sip signals, but is not capable of make a call because the package relays on WebRTC (Which only runs on the browser)
Then I found this question:
Simple SIP phone in nodeJS without WebRTC
Some package called sip was mentioned, I needed to give it a try, and wow, it's pure sip communication, I don't know much about this but still, after a lot of work I manage to connect to my freepbx, authenticate and place a call! Everything seemed to be fine at that point, but now... Where is the audio?
As I understood after a lot of reading the sip only places the call, all the media transmission is performed by RTP, but my question is, how do I implement this? I need to create some RTP media server to handle this or what do I need to do? Any help, clarification or guide on the right direction would be really appreciated, thanks in advance and sorry for my bad English.
Here is my current code:
const sip = require('sip');
const util = require('util');
const digest = require('sip/digest');
const rstring = () => Math.floor(Math.random() * 1e6).toString();
sip.start({
publicAddress: 'My public IP Address',
tcp: false,
logger: {
send: (message, address) => {
debugger;
util.debug("send\n" + util.inspect(message, false, null));
},
recv: (message, address) => {
debugger;
util.debug("recv\n" + util.inspect(message, false, null));
},
error: (message, address) => {
debugger;
util.debug("ERROR\n" + util.inspect(message, false, null));
},
},
});
// Making the call
sip.send({
method: 'INVITE',
version: '2.0',
uri: 'sip:destination@domain.com',
headers: {
to: {
uri: 'sip:destination@domain.com',
},
from: {
uri: 'sip:origin@domain.com',
params: {
tag: rstring(),
},
},
'call-id': rstring(),
cseq: {
method: 'INVITE',
seq: Math.floor(Math.random() * 1e5),
},
'content-type': 'application/sdp',
contact: [
{
uri: 'origin@domain.com',
},
],
},
content: `v=0\r\no=- 234 1 IN IP4 PUBLIC.IP.ADDRESS\r\ns=-\r\nc=IN IP4 PUBLIC.IP.ADDRESS\r\nb=TIAS:13888000\r\nt=0 0\r\nm=audio PORT RTP/AVP 114 0 8 9 112 111 101\r\nb=TIAS:64000\r\nb=AS:64\r\na=rtpmap:114 opus/48000/2\r\na=fmtp:114 minptime=10; useinbandfec=1\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:112 ilbc/8000\r\na=rtpmap:111 speex/16000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:101 0-15\r\na=sendrecv\r\na=rtcp:11801\r\na=ptime:20\r\n`,
},
(rs) => {
if (rs.status === 401) {
// sending ACK
const rq = {
method: 'INVITE',
version: '2.0',
uri: 'sip:destination@domain.com',
headers: {
to: {
uri: rs.headers.to.uri,
},
from: rs.headers.from,
'call-id': rs.headers['call-id'],
cseq: {
method: 'INVITE',
seq: rs.headers.cseq.seq + 1,
},
'content-type': 'application/sdp',
contact: [
{
uri: 'origin@domain.com',
},
],
},
content: `v=0\r\no=- 234 1 IN IP4 PUBLIC.IP.ADDRESS\r\ns=-\r\nc=IN IP4 PUBLIC.IP.ADDRESS\r\nb=TIAS:13888000\r\nt=0 0\r\nm=audio PORT RTP/AVP 114 0 8 9 112 111 101\r\nb=TIAS:64000\r\nb=AS:64\r\na=rtpmap:114 opus/48000/2\r\na=fmtp:114 minptime=10; useinbandfec=1\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:112 ilbc/8000\r\na=rtpmap:111 speex/16000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:101 0-15\r\na=sendrecv\r\na=rtcp:11801\r\na=ptime:20\r\n`,
};
digest.signRequest(rs.headers['www-authenticate'][0], rq, rs, {
user: 'username',
password: 'password',
});
sip.send(rq);
} else {
process.exit(1);
}
});
I have the same problem and I didn't find any solution. So I forked sip.js and changed the source code. It works! I use some node modules instead of native websocket RTC API on the browser. See https://github.com/Winston87245/SIP.js.
According to https://www.rfc-editor.org/rfc/rfc3261 Page 12, you need to understand how SIP (RFC 3261) and SDP (RFC 4566) work.
As far as I know, when client A receives a 200 OK response from B after ringing, client A according to SDP (in an OK response) connects to Client B directly and doesn't need a SIP proxy. In other words, it is a P2P connection. You also need to know ICE (RFC 8445).
I hope this can help you. Feel free to contact me if you have any questions.