How to Play an Audio Stream into a Phone Call with Python
This post has been marked as outdated by our team. It could be that the libraries need to be updated, or that the product has changed.
This blog post shows you, step-by-step, how to play an audio stream into a voice phone call using Python. Two methods for doing this are described in this article:
- Using a Call Control Object (NCCO)
- Using the Voice API (VAPI)
Prerequisites
Assumes you have:
- Python 3 installed
Source Code Repository
The source code for this project is available in the Community GitHub.
Overview
There are various reasons you might want to play an audio stream into a call. A common use case is where you want to put the caller on hold, and to help keep them relaxed, you can play music which gets their stress levels down.
Some example scenarios include:
- Playing caller on-hold music.
- Conference call - play music into a conference call until you have a quorum.
- Prerecorded message - useful where Vonage doesn't support your language in its Text-to-Speech engine.
- Voice mail - when you call and leave a message, the voice message can be played back into a later call.
Below, you will see how to implement scenarios 1 and 2. The other scenarios will be covered by future blog posts.
There are also two methods for playing an audio stream into a call:
- Using a Call Control Object (NCCO)
- Using the Voice API (VAPI)
You will use method 1 for scenario 1, and method 2 for scenario 2.
NCCOs
Call Control Objects (NCCOs) provide a convenient way to control an inbound call.
NCCOs consist of some JSON configuration that describes how to handle the call. There is a detailed reference guide on NCCOs where the many actions that can be carried out are described.
There is only one action we are interested in our scenarios, stream
. There are actually two ways you can use the stream
action: synchronous and asynchronous. Asynchronous means the caller can interrupt the audio stream using the phone keypad.
There are some stream
action options that are of interest:
Option | Description |
---|---|
streamUrl | An array containing a single URL to an MP3 or WAV (16-bit) audio file to stream to the Call or Conversation. |
level | Set the audio level of the stream in the range -1 >=level<=1 with a precision of 0.1. The default value is 0. |
bargeIn | If set to true , this action is terminated when the user presses a button on the keypad. Use this feature to enable users to choose an option without having to listen to the whole message in your Interactive Voice Response (IVR) system. If you set bargeIn to true on one more Stream actions then the next action in the NCCO stack must be an input action. The default value is false . |
loop | The number of times audio is repeated before the Call is closed. The default value is 1. Set to 0 to loop infinitely. |
We won't be looking at the bargeIn
option in this article as that will be covered at a later date.
An example NCCO for playing audio into a call:
[
{
"action": "stream",
"streamUrl": ["https://acme.com/music/relaxing_music.mp3"]
}
]
The audio file formats supported are MP3 and 16-bit WAV.
The Steps
A summary of the procedure you will carry out in this article is as follows:
- Create a Vonage account
- Install Ngrok
- Run Ngrok
- Install Flask
- Install the CLI
- Install the Python client library
- Create a Vonage voice application
- Purchase a number (if you do not have a spare one)
- Assign your number to your application
- Write your Python code to implement the scenario
- Run your application
- Phone your Vonage number
- Listen to the audio streamed into the call
Vonage API Account
To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.
This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.
Install Ngrok
Go to Ngrok and follow the instructions on getting set up.
Run Ngrok
Run Ngrok:
ngrok http 9000
Make a note of the URL that Ngrok is running on. Such as https://1234abcd.ngrok.io
. I am running on port 9000 in my example, but you can use any suitable port.
Install Flask
The example code uses the Flask framework to create a web app that can handle inbound requests.
pip install flask
Install the CLI
npm install nexmo-cli -g
nexmo setup <api_key> <api_secret>
Install the Python Client Library
The client library is a useful tool to have installed if you are working with Nexmo and Python. The client library simplifies the job of making REST API calls - for example, it creates JWTs dynamically for you.
In this article it is used in scenario 2 to make a single VAPI call - "Send Audio".
You can learn how to install the Python Client. The simplest way is to use PIP:
pip install nexmo
Please read the documentation for more details about the Python SDK.
Create a Vonage Voice Application
Create a directory for your project and change into that new directory.
Although you can create a Vonage application in the Dashboard, you can also create one on the command line if you have CLI installed:
nexmo app:create "Blog Voice App" https://1234abcd.ngrok.io/webhooks/answer https://1234abcd.ngrok.io/webhooks/event --keyfile=private.key
Make a note of the generated APPLICATION_ID
, as you will need this later.
A private key is also created in your current directory.
The Answer URL is the URL that Vonage will call back on when a call to a Vonage number is answered.
Nexmo posts event information that helps you monitor your call to the Event URL. In this article the sample code shown just acknowledges the POST, but the event data is not used.
Purchase a Number
If you do not already have a Vonage Number you will need to purchase one.
First search for a suitable number:
nexmo number:search GB
NOTE: You can change the country code to suit your requirements. For example if you are in the US you could use:
nexmo number:search US
Choose a suitable number and then buy it using a command similar to:
nexmo number:buy 442039051952
NOTE: You will need to confirm your purchase.
Assign your number to your application
You now need to associate your Vonage Number with your Nexmo Application:
nexmo link:app YOUR_VONAGE_NUMBER APPLICATION_ID
Write Your Python Code
For the two scenarios you will see a different method for playing an audio stream into the call:
- Scenario 1 - play audio into a call - using an NCCO
- Scenario 2 - play audio into a conference call - using VAPI
Multiple methods are provided to allow for flexibility, but you can use whichever method is simplest for your use case.
Scenario 1
In this scenario, you will call a Nexmo number and music will be streamed into your call using an NCCO with a stream
action.
Add the following to a new file and save it as scenario-1.py
:
from flask import Flask, request, jsonify
audio_url = "https://your_domain.com/music/your_music.mp3"
app = Flask(__name__)
ncco = [
{
"action": "stream",
"streamUrl": [audio_url]
}
]
@app.route("/webhooks/answer")
def answer_call():
return jsonify(ncco)
@app.route("/webhooks/event", methods=['POST'])
def events():
return ("200")
if __name__ == '__main__':
app.run(host="localhost", port=9000)
You can also find the latest version of this code in the GitHub repo.
Note: In the previous code make sure you set your own URL for the music file you wish to stream into the call.
Try It Out
You can run your code locally using:
python3 scenario-1.py
The sequence of events in this scenario is as follows:
- Dial your Vonage Number.
- Nexmo receives the call.
- A callback is generated on the Answer webhook URL you specified.
- Your application receives the callback and responds with an NCCO.
- Music is played into your call.
Scenario 2
In this scenario, you call your Vonage number and you are joined into a conference. You can then navigate to the /stream
URL to initiate streaming into the conference. Music is then played into your conference using VAPI.
Add the following to a new file and save it as scenario-2.py
:
from flask import Flask, request, jsonify
import nexmo
audio_url = "https://your_domain.com/music/your_music.mp3"
APPLICATION_ID = "YOUR_APP_ID"
PRIVATE_KEY = "private.key"
CONF_NAME = "Relaxing Conference"
uuid = ""
ncco = [
{
"action": "talk",
"text": "Please wait while we connect you to the conference"
},
{
"action": "conversation",
"name": CONF_NAME
}
]
app = Flask(__name__)
@app.route("/webhooks/answer")
def answer_call():
global uuid, in_conf
uuid = request.args['uuid']
print("UUID:====> %s" % uuid)
return (jsonify(ncco))
@app.route("/webhooks/event", methods=['POST'])
def events():
return ("200")
@app.route("/stream")
def stream():
client = nexmo.Client(application_id = APPLICATION_ID, private_key=PRIVATE_KEY)
client.send_audio(uuid, stream_url=[audio_url])
return ("200")
if __name__ == '__main__':
app.run(host="localhost", port=9000)
You can also find the latest version of this code in the GitHub repo.
Note: In the previous code make sure you set your own Application ID and the URL for the music file you want to stream.
Try It Out
You can run your code locally using:
python3 scenario-2.py
The sequence of events in this scenario is as follows:
- Dial your Nexmo Number.
- Nexmo receives the call.
- A callback is generated on the Answer webhook URL you specified.
- Your application receives the callback and responds with an NCCO.
- You are joined into a conference.
- Navigate to
localhost:9000/stream
and music will be played into your conference.
Summary
In this article you have seen how to stream audio into a call by means of both an NCCO and a VAPI call.
Next steps
For next steps you could use these techniques to implement your own voice mail system. It would be helpful to look at Vonage's documentation on recordings. There are also some examples to get you started quickly:
Resources
For more information:
- You can check out the full documentation for NCCOs to learn many ways to control your call.
- You can learn about the REST API for Voice, known as VAPI.