如何通过nodejs进行SIP呼叫

时间:2019-08-17 02:19:07

标签: node.js webrtc dialogflow sip rtp

我正在尝试向客户进行自动呼叫,我已经设置好了freepbx并可以正常工作,现在我希望能够触发一些nodejs代码来进行呼叫,获取音频流并将其传递给dialogflow和根据对白流程响应,向客户播放MP3(或任何其他音频类型)。

我已经尝试过此软件包:

https://github.com/versatica/JsSIP

我可以稳定通话并获取音频流。是的,那很好,即使不是在浏览器中的html中也没有。。。但是我发现了!

https://github.com/versatica/jssip-node-websocket

看起来像我所有问题的答案,直到我尝试从自己的nodejs脚本发出呼叫为止,令人惊讶,它不起作用,甚至不打算起作用,它只是用于发送sip信号,但不能之所以打个电话,是因为该程序包在WebRTC上中继(仅在浏览器上运行)

然后我发现了这个问题:

Simple SIP phone in nodeJS without WebRTC

提到了一些名为sip的程序包,我需要尝试一下,哇,这是纯粹的sip通讯,对此我不太了解,但是经过大量工作之后,我设法连接到了我的freepbx,验证并拨打电话!!那时一切似乎都很好,但是现在...音频在哪里?

据我了解,在大量阅读sip之后,所有的媒体传输都是由RTP执行的,但是我的问题是,我该如何实现呢?我需要创建一些RTP媒体服务器来处理此问题,或者我需要做什么?非常感谢您对正确方向的任何帮助,澄清或指导,在此先感谢您,我的英语不好。

这是我当前的代码:

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);
  }
});

2 个答案:

答案 0 :(得分:2)

我遇到了同样的问题,但没有找到任何解决方案。因此,我分叉了sip.js并更改了源代码。有用!我在浏览器上使用了一些节点模块,而不是本机的websocket RTC API。 参见https://github.com/Winston87245/SIP.js

根据https://tools.ietf.org/html/rfc3261第12页,您需要了解SIP(RFC 3261)和SDP(RFC 4566)的工作方式。

据我所知,当客户端A振铃后收到来自B的200 OK响应时,根据SDP的Client A(处于OK响应中)直接连接到Client B,不需要SIP代理。换句话说,它是一个P2P连接。您还需要了解ICE(RFC 8445)。

我希望这可以为您提供帮助。如有任何疑问,请随时与我联系。

答案 1 :(得分:0)

Asterisk

我知道使用星号的唯一方法。这是开源的SIP和RTP服务器等等。您只需要在nodejs中维护调用状态。将该Sip消息传递给Asterisk,并在sip标头中添加您自己的联系人,然后Asterisk将使用sdp负载将呼叫返回给您。

SDP

sdp有效负载告诉媒体服务器RTP在哪里以及如何通过网络从甲方传播到乙方,反之亦然。一旦sip连接建立,RTP流将根据sdp传输。

Call flow :

甲方 ==> Nodejs(sip.js) ==> 星号 ==> Nodejs(sip.js ) ==> 乙方

对于甲方和乙方,您可以使用XLite或任何其他VOIP拨号器。