Call a WebSocket

Using Nexmo’s Voice API you can connect PSTN calls to WebSocket endpoints. This means that any app that hosts a WebSocket server can now be a participant in a Nexmo voice conversation. Voice API removes all the hard work, a WebSocket is just another endpoint that you connect to using NCCOs or an API call.

WebSocket is a computer communications protocol that provides full-duplex communication channels over a single TCP connection. WebSocket is implemented in Web browsers and web servers. For example, the Firefox and Google Chrome browsers, and the Tornado Web server.

Easy WebSocket connections using Voice API enables some innovative use cases, including easily integrating:

  • Artificial intelligence engines and bots that can be conferenced into a meeting to enable faster decision making.
  • Analysis engines into voice calls to determine sentiment.
  • Bots that:
    • Make outbound calls to accomplish simple tasks such as making a restaurant reservation or more complex ones, such as requesting information from field experts.
    • Take inbound calls and make their expertise more readily available. For example, a doctor in a small village in Tanzania can call a medical expert bot and get access to the same medical advice available to specialists at the Mayo Clinic.
  • Third party voice recognition, recording, and transcription engines.

In this section you see how to easily test a Voice API connect to a WebSocket endpoint. You create a NCCO that connects an inbound PSTN call to the echo server using WebSocket and a dual function server that provisions NCCOs and echos voice messages back to a Websocket:

Prerequisites

To follow the steps in this section you need a:

Create an echo server

The echo server provides the NCCO used by Nexmo to connect to a WebSocket and the WebSocket Voice API connects to.

When Voice API connects to a WebSocket endpoint, Nexmo makes an initial HTTP GET request for a WebSocket. The server responds with an HTTP 101 to switch protocols, the connection is upgraded to WebSocket. At that point you have a persistent TCP connection between Nexmo and the echo server. The initial message sent by Nexmo is plain text with metadata. Other text messages are send mid-stream. You should inspect each message to determine if it contains text or binary data and parse binary frames only as audio.

When a message is received, the echo server tests if it binary. If so, it is echoed to the originator. Once the connection is established, fully bidirectional messages can originate from either end and do not need a response. Text messages are printed to the console. When the client terminates the connection it is removed from the list.

In a real world implementation, you either record the binary message to a file or pass the data to some audio processing code. You can also send audio back to the call at any point. You do not have to respond to an incoming message.

To create and run your echo server:

  1. Depending on the language you use, copy the following code to a local file echo_server:
    #!/usr/bin/env python
    import tornado.httpserver
    import tornado.websocket
    import tornado.ioloop
    import tornado.web
    
    class WSHandler(tornado.websocket.WebSocketHandler):
        connections = []
        def open(self):
            print("client connected")
            #Add the connection to the list of connections
            self.connections.append(self)
        def on_message(self, message):
            #Check if message is Binary or Text
            if type(message) == str:
                print("Binary Message recieved")
                #Echo the binary message back to where it came from
                self.write_message(message, binary=True)
            else:
                print(message)
                #Send back a simple "OK"
                self.write_message('ok')
        def on_close(self):
            #Remove the connection from the list of connections
            self.connections.remove(self)
            print("client disconnected")
    
    class NCCOHandler(tornado.web.RequestHandler):
        def get(self):
            with open("ncco.json", 'r') as f:
                ncco = f.read()
            self.write(ncco)
            self.set_header("Content-Type", 'text/json')
            self.finish()
    
    application = tornado.web.Application([(r'/socket', WSHandler),
                                            (r'/ncco', NCCOHandler)])
    if __name__ == "__main__":
        http_server = tornado.httpserver.HTTPServer(application)
        http_server.listen(8000)
        tornado.ioloop.IOLoop.instance().start()
    
    Tornado is a Python web framework and asynchronous networking library. It is ideal for long polling, WebSockets, and other applications that require a long-lived connection to each user. To install it, call: pip install tornado
    var WebSocketServer = require('websocket').server;
    
    var http = require('http');
    var HttpDispatcher = require('httpdispatcher');
    var dispatcher     = new HttpDispatcher();
    const fs = require('fs');
    
    //Create a server
    var server = http.createServer(handleRequest);
    
    var wsServer = new WebSocketServer({
        httpServer: server,
        autoAcceptConnections: true,
    
    });
    
    //Lets use our dispatcher
    function handleRequest(request, response){
        try {
            //log the request on console
            console.log(request.url);
            //Dispatch
            dispatcher.dispatch(request, response);
        } catch(err) {
            console.log(err);
        }
    }
    
    // Serve the ncco
    dispatcher.onGet("/ncco", function(req, res) {
        fs.readFile('./ncco.json', function(error, data) {
           res.writeHead(200, { 'Content-Type': 'application/json' });
           res.end(data, 'utf-8');
        });
    });
    
    wsServer.on('connect', function(connection) {
        console.log((new Date()) + ' Connection accepted' + ' - Protocol Version ' + connection.webSocketVersion);
        connection.on('message', function(message) {
            if (message.type === 'utf8') {
                // Reflect the message back
                console.log(message.utf8Data);
            }
            else if (message.type === 'binary') {
                console.log("Binary Message Recieved");
                // Reflect the message back
                connection.sendBytes(message.binaryData);
            }
        });
        connection.on('close', function(reasonCode, description) {
            console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
        });
    });
    
    //Lets start our server
    server.listen(8000, function(){
        //Callback triggered when server is successfully listening. Hurray!
        console.log("Server listening on: http://localhost:%s", 8000);
    });
    
    To run this code sample you need to install: npm install http websocket httpdispatcher.
  2. If you are running the server locally, open an http tunnel to the echo server:
    ngrok http 8000
  3. Note the URL to your echo server.
  4. Depending on the language you use, run the echo server:
    • python echo_server.py
    • node echo_server.js

Connect a PSTN call to a WebSocket

In Voice API, a WebSocket is just another endpoint. When you call the virtual number associated with your application, the NCCO at answer_url tells Voice API to connect your inbound call to the echo server using a WebSocket. When you call your virtual number, you hear a reply given by somebody intelligent, witty and attractive.

To connect an inbound PSTN call to the echo server using a WebSocket:

  1. Use the following template to create ncco.json. This file contains the NCCO to connect an incoming PSTN call to a WebSocket:
    [
      {
        "action": "talk",
        "text": "Please wait while we connect you"
      },
      {
        "action": "connect",
        "eventUrl": [
          "https://example.com/events"
        ],
        "from": "441632960960",
        "endpoint": [
        {
          "type": "websocket",
          "uri": "ws://example.com/socket",
          "content-type": "audio/l16;rate=16000",
          "headers": {
            "whatever": "metadata_you_want"
            }
          }
        ]}
    ]
    
  2. Place ncco.json in the same directory as echo_server.py.
  3. Ensure that answer_url for your Application is pointing to the echo server. If not, use the Nexmo CLI or Application API to update answer_url.
  4. Call the virtual number associated with your Application and listen to your own words of wisdom.

And that is it. Using Voice API you have connected a PSTN call to a WebSocket.

Previous   Next