Stream Audio into a Phone Call with Node.js

Stream Audio into a Phone Call with Node.js

Published January 30, 2019 by Mark Lewin
Categories:

When you have your customer on a voice call, you have her undivided attention. Why not use that opportunity to tell her the latest news about your company, relay an inspiring message from your CEO, or even just play her your latest advertising jingle?

In this blog post you will learn how to play an audio file into an active call programmatically, using the Nexmo Voice API and Node.js.

Before you Begin

To work through this example you’ll need Node.js. If you don’t already have it installed, download it from the Node.js website.

You must have a Nexmo account. Sign up now if you don’t already have one.

You’ll also need a Nexmo number to call from, which you can purchase with the free credit Nexmo gives you when you sign up.

You can provision a number in the Developer Dashboard, but we’ll talk you through using the Nexmo CLI to rent a number, create a voice application and then link your number to it.

Finally, you’ll want the source code, which is available on GitHub. Clone the repository and cd into the application’s root directory.

Installing the Nexmo CLI

Install the Nexmo CLI globally using the following command:

Then, configure the CLI with your Nexmo API key and secret, which you will find in the Developer Dashboard:

Replace the NEXMO_API_KEY and NEXMO_API_SECRET with your own details to authenticate the CLI.

Renting a Nexmo Number

You need a number to make calls from. Rent one by executing the following command, replacing the country code as appropriate. For example, if you are in the USA, replace GB with US:

Make a note of the telephone number that the command returns.

Creating the Voice Application

To use the Voice API, you must create a Voice API application. This is not the same thing as the web application you are building. It is merely a container for the configuration and security information you need to connect to Nexmo’s APIs.

Create an application using the CLI and make a note of the application ID it returns:

Note that the app:create command shown uses a few parameters. These are to set the webhook endpoints and download your private key to authenticate your application.

The Nexmo APIs need to know your webhook endpoints so that they can make requests to them when there is an incoming call, or an event that your application should know about. You can safely leave these as example.com because we will specify the webhooks programmatically.

Initialize the Dependencies

The application has the following external dependencies:

  • dotenv – a module that allows us to easily configure the application using a .env file
  • express – a lightweight web framework
  • body-parser – middleware to handle POST requests
  • nexmo – the REST client library for Node.js

These dependencies are configured in package.json. Run npm install to install them to the node_modules subdirectory.

Make your Application Available on the Public Internet

We need to expose our application to the Internet so that Nexmo’s servers can access our webhooks. We recommend using ngrok for this.

Follow the instructions in this blog post to install and run ngrok on port 3000. For example:

ngrok will give you a temporary URL such as https://914288e7.ngrok.io. Make a note of it.

Leave ngrok running while you are using the application, otherwise, the URLs will change and you will need to reconfigure it.

Configure the Environment

Copy example.env to .env and enter the details you have harvested from the above steps:

Then, change the path to the audio file in the answer.json package to match your ngrok hostname:

You are now ready to see the application in action!

Run the Application

Launch the application by executing the following command:

Visit http://localhost:3000/call in your browser. This makes a GET request to the /call endpoint in your application and causes it to ring the TO_NUMBER in .env.

You will hear a message, followed by some music that plays for 20 seconds and then the call disconnects.

How It Works

All the logic happens in server.js.

Instantiating the Nexmo Client

The application first reads the settings you configured in .env into environment variables and uses them to instantiate the Nexmo REST API client library for Node.js:

Serving the Audio Files and NCCO

We use two audio files in this application. One is for the music that we play to the caller. The other is a silent MP3 file. You can only play audio into an existing call, so it’s important that we keep the call open otherwise it will disconnect before you have a chance to do anything with it. The silent MP3 file keeps the call open.

The welcome message and silent MP3 are defined in a Nexmo Call Control Object (NCCO). The NCCO is an array of JSON objects that represents the actions that occur within the call. Our answer.json NCCO tells the application to read some text and then stream a silent MP3:

This is one way of streaming audio into a call. But the focus of this post is how to do it programmatically.

These resources are served from the application’s public directory as follows:

Making the Outbound Call

When we make a GET request to the /call route, the application uses the nexmo client library’s calls.create() method to make an outbound call to the TO_NUMBER configured in .env. When the call is answered, it responds with the actions defined in the answer.json NCCO and starts listening to Voice API events on the /webhooks/events webhook handler:

Playing Audio into the Call

In the event webhook, we check the call status. If it is answered, then we retrieve the call ID so that we can play the audio into the correct call and stop playing the audio after 20 seconds. After the audio is stopped, we use the nexmo.calls.update() method to replace the existing NCCO action with a new one: hangup, which disconnects the call:

The start_stream() function uses the Nexmo client library’s calls.stream.start() method to programmatically play the specified audio file into the call:

The stop_stream() function calls nexmo.calls.stream.stop() to stop playing the audio file:

Conclusion

In this post, you learned how to play audio into an existing call and about some of the NCCO actions that govern the call flow. Feel free to experiment by substituting different audio files and NCCO actions. The following resources might help:

Leave a Reply

Your email address will not be published.