如何将 Asterisk ARI 与 socket.io 和 Node.js 一起使用

Posted

技术标签:

【中文标题】如何将 Asterisk ARI 与 socket.io 和 Node.js 一起使用【英文标题】:How to use Asterisk ARI with socket.io & Node.js 【发布时间】:2016-01-02 07:27:24 【问题描述】:

最近开始接触星号、Linux、node.js 和最近的 socket.io,以便我最终可以为星号制作实时 Web 应用程序。

所以作为一个有根据的猜测,Node.js 有点像 Asterisk 和 Socket 之间的中间人。但我不知道如何通过 socket.io 将信息从星号提取到网页。

我一直在研究 socket.io 并且在如何将它们相互链接上已经不知所措了几天,这样我就可以记录停滞中发生的事件或在电话会议中拉出当前通话,只是任何事情在这一点上,由于据我所知 ARI 相对较新,因此很难弄清楚。

我在下面链接了 3 个文件,让您了解所做的工作,bridge-mixed.js 是基于星号 ARI 文档中给出的示例。

我可以通过node.js运行文件,拨打我在extensions.conf文件中指定的分机号,当第一个用户进入会议时播放音乐,一旦超过1个用户进入则停止音乐。

至于其他两个文件,它只是一个基本的 socket.io 应用程序,已通过 YouTube 指南逐步完成以了解其工作原理。

我只需要一个简单的例子来说明如何塑造它们或使它们一起工作,就可以开始为星号制作实时 Web 应用程序了。

即使我能够以某种方式通过 socket.io 和 Node.js 将停滞事件拉到网页上。

希望你们能提供一些见解或指导,因为此刻我真的迷失了。

bridge-mixed.js

    /*jshint node:true*/
'use strict';

var ari = require('ari-client');
var util = require('util');
var chanArr =[];

ari.connect('http://localhost:0001', 'asterisk', 'asterisk', clientLoaded);

// handler for client being loaded
function clientLoaded (err, client) 
  if (err) 
    throw err;
  

  // find or create a holding bridge
  var bridge = null;
  client.bridges.list(function(err, bridges) 
    if (err) 
      throw err;
    

    bridge = bridges.filter(function(candidate) 
      return candidate.bridge_type === 'mixing';
    )[0];

    if (bridge) 
      console.log(util.format('Using bridge %s', bridge.id));
     else 
      client.bridges.create(type: 'mixing', function(err, newBridge) 
        if (err) 
          throw err;
        

        bridge = newBridge;
        console.log(util.format('Created bridge %s', bridge.id));
      );
    
  );

  // handler for StasisStart event
  function stasisStart(event, channel) 
    console.log(util.format(
        'Channel %s just entered our application, adding it to bridge %s',
        channel.name,
        bridge.id));



    channel.answer(function(err) 
      if (err) 
        throw err;
      

      bridge.addChannel(channel: channel.id, function(err) 
        chanArr.push(channel)

        if (err) 
          throw err;
         


        //If else statement to start music for first user entering channel, music will stop once more than 1 enters the channel.
 if(chanArr.length <= 1)
        bridge.startMoh(function(err) 
          if (err) 
            throw err;
          
        );
      else
        bridge.stopMoh(function(err) 
          if (err) 
            throw err;
          
        );
      

      );
    );
  

  // handler for StasisEnd event
  function stasisEnd(event, channel)         
    chanArr = null;
    console.log(util.format(
        'Channel %s just left our application', channel.name));
  

  client.on('StasisStart', stasisStart);
  client.on('StasisEnd', stasisEnd);

  client.start('bridge-hold');

那么下面是一个非常基本的socket.io功能和html页面:

app.js

    var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server),
nicknames = [];

server.listen(0001);

app.get('/', function (req, res) 
    res.sendfile(__dirname + '/index.html');
);

io.sockets.on('connection', function (socket) 
    socket.on('new user', function (data, callback) 
        if (nicknames.indexOf(data) != -1) 
            callback(false);
         else 
            callback(true);
            socket.nickname = data;
            nicknames.push(socket.nickname);
            updateNicknames();
        
    );

    function updateNicknames() 
        io.sockets.emit('usernames', nicknames);
    

    socket.on('send message', function (data) 
        io.sockets.emit('new message', 
            msg : data,
            nick : socket.nickname
        );
    );

    socket.on('disconnect', function (data) 
        if (!socket.nickname)
            return;
        nicknames.splice(nicknames.indexOf(socket.nickname), 1);
        updateNicknames();
    );
);

index.html

<html>
    <head>
        <title> Chat with socket.io and node.js</title>
        <style>
            #chat
            height:500px;
            

            #contentWrap
            display:none;
            

            #chatWrap
            float:left;
            border:1px #000 solid;
            

            .error
            color:red;
            

            .whisper
            color:gray;
            font-style:italic;
            


        </style>
    </head>
    <body>

        <div id="nickWrap">
            <p>Enter a Username</p>
            <p id="nickError"></p>
            <form id="setNick">
                <input size="35" id="nickname"></input>
                <input type="submit"></input>
            </form>
        </div>

        <div id="contentWrap">
            <div id="chatWrap">
                <div id="chat"></div>
                <form id="send-message">
                    <input size="35" id="message"></input>
                    <input type="submit"></input>
                </form> 
            </div>
            <div id="users"></div>
        </div>

        <script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
        <script src="https://cdn.socket.io/socket.io-1.3.6.js"></script>
        <script>
            jQuery(function($)
            var socket = io.connect();
            var $nickForm = $('#setNick');
            var $nickError = $('#nickError');
            var $nickBox = $('#nickname');
            var $users = $('#users');
            var $messageForm = $('#send-message');
            var $messageBox = $('#message');
            var $chat = $('#chat');

            $nickForm.submit(function(e)
            e.preventDefault();
            socket.emit('new user', $nickBox.val(), function(data)
            if(data)
            $('#nickWrap').hide();
            $('#contentWrap').show();
             else
            $nickError.html('That username is already taken! Try Again.');
            
            );
            $nickBox.val('');
            );

            socket.on('usernames', function(data)
            var html ='';
            for(i=0; i < data.length; i++)
                    html += data[i] + '<br/>'
                    
                    $users.html(html);
                    );

                    $messageForm.submit(function(e)
                    e.preventDefault();
                    socket.emit('send message', $messageBox.val(), function(data)
                    $chat.append('<span class="error"><b>' + data + "</span><br/>");
                        );
                        $messageBox.val('');
                        );

                        socket.on('new message', function(data)
                        $chat.append('<span class="msg"><b>' + data.nick + ': </b>' + data.msg + "</span><br/>");
                        );

                        socket.on('whisper', function(data)
                        $chat.append('<span class="whisper"><b>' + data.nick + ': </b>' + data.msg + "</span><br/>");
                        );

                        );
                    </script>
                </body>
            </html>

【问题讨论】:

【参考方案1】:

因此,经过一些尝试和错误,可以通过有效地合并 bridge-mixed.js 和 app.js 文件让它们一起工作。完成此操作后,我可以开始通过 ARI 客户端访问星号端的信息,并开始通过 socket.io 将其传递给充当星号前端的实时 Web 应用程序。

当前发布的代码只是将当前调用者姓名附加到网页,但它是一个基本示例,它应该是一个很好的垫脚石,看看你可以用它做什么,因为那里的信息可以很容易地开始使用JQuery 开始做所有好事......例如静音呼叫,桥接从会议中踢出的用户。这些是目前正在进行的工作,将来会更新。

我希望这对某人有所帮助。

app.js(ARI 客户端和 Socket.io 服务器端)

ARI 函数和 socket.io 服务器端。

var ari = require('ari-client');
var util = require('util');
var chanArr = [];
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);

//ARI client
ari.connect('http://localhost:8088', 'asterisk', 'asterisk', clientLoaded);

function clientLoaded(err, client) 
    if (err) 
        throw err;
    
    // find or create a holding bridges
    var bridge = null;
    client.bridges.list(function (err, bridges) 
        if (err) 
            throw err;
        

        bridge = bridges.filter(function (candidate) 
                return candidate.bridge_type === 'mixing';
            )[0];

        if (bridge) 
            console.log(util.format('Using bridge %s', bridge.id));
         else 
            client.bridges.create(
                type : 'mixing'
            , function (err, newBridge) 
                if (err) 
                    throw err;
                

                bridge = newBridge;
                console.log(util.format('Created bridge %s', bridge.id));
            );
        
    );

    // handler for StasisStart event
    function stasisStart(event, channel) 
        console.log(util.format(
                'Channel %s just entered our application, adding it to bridge %s',
                channel.name,
                bridge.id));

        channel.answer(function (err) 
            if (err) 
                throw err;
            

            bridge.addChannel(
                channel : channel.id
            , function (err) 
                var id = chanArr.push(channel.name)
                    console.log("User: " + channel.name);
                if (err) 
                    throw err;
                

                //If else statement to start music for first user entering channel, music will stop once more than 1 enters the channel.
                if (chanArr.length <= 1) 
                    bridge.startMoh(function (err) 
                        if (err) 
                            throw err;
                        
                    );
                 else 
                    bridge.stopMoh(function (err) 
                        if (err) 
                            throw err;
                        
                    );
                

            );
        );
    

    // handler for StasisEnd event
    function stasisEnd(event, channel) 
        chanArr = null;
        console.log(util.format(
                'Channel %s just left our application', channel.name));
    
    client.on('StasisStart', stasisStart);
    client.on('StasisEnd', stasisEnd);
    client.start('bridge-hold');


//Socket.io logic here
server.listen(3009, function () 
    console.log('listening on *:3009');
);

app.use(express.static(__dirname + '/public'));
app.get('/', function (req, res) 
    res.sendfile(__dirname + "/testPage.html");
);

io.sockets.on('connection', function () 
    updateSip();
);

function updateSip() 
    io.sockets.emit('sip', chanArr);

testPage.html

Web 应用程序前端。

<html>
    <head>
        <title> Chat with socket.io and node.js</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
            <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
                <link href="https://gitcdn.github.io/bootstrap-toggle/2.2.0/css/bootstrap-toggle.min.css" rel="stylesheet">
                    <link href="/css/style.css" rel="stylesheet" type="text/css">   
                    </head>
                    <body>

                        <nav class="navbar navbar-inverse navbar-fixed-top">
                            <div class="navbar-header">
                                <div class="navbar-brand">Asterisk ARI Test Application</div>
                            </div>
                            <div id="navbar" class="navbar-collapse collapse">
                            </div>
                        </nav>

                        <div class="main-bridge">
                            <div class="container">
                                <div class="jumbotron content-A">
                                    <form class="test-ari">
                                        <p class="lead">Enter the number you want to call.</p>
                                        <div class="input-group input-group-lg">
                                            <input type="tel" class="form-control" placeholder="Phone Number" aria-describedby="sizing-addon1" required="" /> 
                                            <span class="input-group-btn">
                                                <button class="btn btn-default" type="submit">Call Back Now</button>
                                            </span>
                                        </div>
                                    </form>
                                </div>
                            </div>
                        </div>

                        <div class="secondary-bridge" id="sip">
                            <h3 class="conf-head">Conference call</h3>
                            <div class="panel panel-default ">
                                <div class="panel-heading " >
                                    <h3 class="panel-title"><div id="sip"></div></h3>
                                </div>
                                <div class="panel-body">
                                    <input type="checkbox" data-on="Voice" data-off="Muted" checked data-toggle="toggle" data-onstyle="success" data-offstyle="danger">
                                        <button class="btn btn-default kick" id="kick" data-toggle="modal" data-target="#myModal" type="submit">Kick</button>
                                    </div>
                                </div>
                            </div>

                            <!-- Modal -->
                            <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                                <div class="modal-dialog" role="document">
                                    <div class="modal-content">
                                        <div class="modal-header">
                                            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                                            <h4 class="modal-title" id="myModalLabel">Kick user</h4>
                                        </div>
                                        <div class="modal-body">
                                            Are you you want to kick this user?
                                        </div>
                                        <div class="modal-footer">
                                            <button type="button" class="btn btn-default" data-dismiss="modal">No</button>
                                            <button type="button" class="btn btn-primary">Yes</button>
                                        </div>
                                    </div>
                                </div>
                            </div>

                            <footer class="footer">
                                <p>&copy; User 2015</p>
                            </footer>

                            <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> 
                            <script src="https://gitcdn.github.io/bootstrap-toggle/2.2.0/js/bootstrap-toggle.min.js"></script>
                            <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
                                <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
                                <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> 
                                <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> 
                                <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> 
                                <script src="https://cdn.socket.io/socket.io-1.3.6.js"></script>
                                <script src="/js/test.js"></script>

                            </body>
                        </html>

test.js

Socket.io 客户端和其他一些 JQuery。

jQuery(function ($) 
    var socket = io.connect();
    var $sip = $('#sip');
    socket.on('sip', function (data) 
        var sip = '';
        for (i = 0; i < data.length; i++) 
            sip += data[i] + '<br/>'
        
        $sip.append('<h3 class="conf-head">Conference call</h3> \
                                        <div class="panel panel-default ">\
                                            <div class="panel-heading " >\
                                                <h3 class="panel-title">' + sip + '</h3>\
                                            </div>\
                                            <div class="panel-body">\
                                                <input type="checkbox" data-on="Voice" data-off="Muted" checked data-toggle="toggle" data-onstyle="success" data-offstyle="danger">\
                                                    <button class="btn btn-default kick" id="kick" data-toggle="modal" data-target="#myModal" type="submit">Kick</button>\
                                                </div>\
                                            </div>');

    );

    $('.kick').click(function () 
        $('#myInput').focus()
    );
);

【讨论】:

我正在使用这个例子,但是当我打电话时我没有收到任何结果。 wscat -c "ws://localhost:8088/ari/events?api_key=user:secret&amp;app=my-app" 我收到了.. 你知道为什么吗?

以上是关于如何将 Asterisk ARI 与 socket.io 和 Node.js 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

为啥Adjusted rand index(ARI)优于rand index(RI)以及如何从公式中直观理解ARI

PhoneRTC Signal and Turn 服务器与 Asterisk 服务器

linux asterisk 啥东西

Lync sdk 与 Asterisk 一起使用?

将 AsteriskNOW 升级到 Asterisk 12

asterisk如何配置视频通话?