Giter VIP home page Giter VIP logo

voice-javascript-sdk-quickstart-python's Introduction

Twilio

Twilio Voice JavaScript SDK Quickstart for Python

This template is part of Twilio CodeExchange. If you encounter any issues with this code, please open an issue at github.com/twilio-labs/code-exchange/issues.

About

This application should give you a ready-made starting point for writing your own voice apps with the Twilio Voice JavaScript SDK (formerly known as Twilio Client).

This application uses the lightweight Flask Framework. Once you set up the application, you will be able to make and receive calls from your browser. You will also be able to switch between audio input/output devices, and see dynamic volume levels on the call.

screenshot of application homepage

Implementations in other languages:

.NET Java Node PHP Ruby
Done Done Done Done Done

Set Up

Requirements

Twilio Account Settings

Before we begin, we need to collect all the config values we need to run the application.

Config Value Description
TWILIO_ACCOUNT_SID Your primary Twilio account identifier - find this in the console here.
TWILIO_TWIML_APP_SID The TwiML application with a voice URL configured to access your server running this app - create one in the console here. Also, you will need to configure the Voice "REQUEST URL" on the TwiML app once you've got your server up and running.
TWILIO_CALLER_ID A Twilio phone number in E.164 format - you can get one here
API_KEY / API_SECRET Your REST API Key information needed to create an Access Token - create an API key here. The API_KEY value should be the key's SID.

Local development

  1. First, clone this repository and cd into it.

    git clone https://github.com/TwilioDevEd/voice-javascript-sdk-quickstart-python.git
    cd voice-javascript-sdk-quickstart-python
  2. Run make install. This command will create a Python virtual environment, load it, and install the Python dependencies.

    make install
  3. Download the Twilio Voice JavaScript SDK code from GitHub.

    In a production environment, we recommend using npm to install the SDK. However, for the purposes of this quickstart, we are not introducing Node or build tools, and are instead getting the SDK code directly from GitHub.

    See the instructions here for downloading the SDK code from GitHub. You will download a zip or tarball for a specific release version of the Voice JavaScript SDK (ex: 2.0.0), extract the files, and retrieve the twilio.min.js file from the dist/ folder. Move that twilio.min.js file into this project's static/ directory.

  4. Create a configuration file for your application by copying the .env.example file to a new file called .env. Then, edit the .env file to include your account and application details.

    cp .env.example .env

    See Twilio Account Settings to locate the necessary environment variables.

    Windows (PowerShell)

    Begin by creating a configuration file for your application:

    cp .env.example.ps1 .env.ps1

    Edit .env.ps1 with the four configuration parameters we gathered from above. "Dot-source" the file in PowerShell like so:

    . .\.env.ps1

    This assumes you will run the application in the same PowerShell session. If not, edit the .env.ps1 and uncomment the [Environment]::SetEnvironmentVariable calls. After re-running the script, the environment variables will be peramently set for your user account.

  5. Run the application. It will run locally on port 5000.

    make serve
  6. Navigate to http://localhost:5000

  7. Expose your application to the wider internet using ngrok. You can click here for more details. This step is important and your application won't work if you only run the server on localhost.

    ngrok http 5000
  8. When ngrok starts up, it will assign a unique URL to your tunnel. It might be something like https://asdf456.ngrok.io. Take note of this.

  9. Configure your TwiML app's Voice "REQUEST URL" to be your ngrok URL plus /voice. For example:

    screenshot of twiml app

    Note: You must set your webhook urls to the https ngrok tunnel created.

You should now be ready to rock! Make some phone calls or receiving incoming calls in the application. Note that Twilio Client requires WebRTC enabled browsers, so Edge and Internet Explorer will not work for testing. We'd recommend Google Chrome or Mozilla Firefox instead.

Your Web Application

When you navigate to localhost:5000, you should see the web application containing a "Start up the Device" button. Click this button to initialize a Twilio.Device.

screenshot of application homepage

When the Twilio.Device is initialized, you will be assigned a random client name, which will appear in the top left corner of the homepage. This client name is used as the identity field when generating an access token for the client, and is also used to route incoming calls to the correct client device.

To make an outbound call to a phone number:

Under "Make a Call", enter a phone number in E.164 format and press the "Call" button.

To make a browser-to-browser call:

Open two browser windows to localhost:5000 and click "Start up the Device" button in both windows. You should see a different client name in each window.

Enter one client's name in the other client's "Make a Call" input field, and press the "Call" button.

screenshot of browser-to-browser calling

Receiving incoming calls from a non-browser device:

You will first need to configure your Twilio Voice phone number (the phone number you used as the TWILIO_CALLER_ID configuration value) to route incoming calls to your TwiML app. This tells Twilio how to handle an incoming call directed to your Twilio Voice number.

  1. Log in to the Twilio Console
  2. Navigate to your Active Number list
  3. Click on the number you are using as your TWILIO_CALLER_ID.
  4. Scroll down to find the "Voice & Fax" section and look for "CONFIGURE WITH".
  5. Select "TwiML App".
  6. Under "TwiML App", choose the TwiML App you created earlier for this quickstart.
  7. Click the "Save" button at the bottom of the browser window.

screenshot of configuring phone number for incoming calls

You can now call your Twilio Voice phone number from your phone.

Note: Since this is a quickstart with limited functionality, incoming calls will only be routed to your most recently created Twilio.Device.

Unknown Devices

If you see "Unknown Audio Output Device 1" in the "Ringtone" or "Speaker" devices lists, click the button below the boxes (Seeing "Unknown" Devices?) to have your browser identify your input and output devices. screenshot of unknown devices

Docker

If you have Docker already installed on your machine, you can use our docker-compose.yml to setup your project.

  1. Make sure you have the project cloned and that Docker is running on your machine.
  2. Retrieve the twilio.min.js file and move it to the static directory as outlined in Step 3 of the Local Development steps.
  3. Setup the .env file as outlined in Step 4 of the Local Development steps.
  4. Run docker-compose up.
  5. Follow the steps in Local Development on how to expose your port to Twilio using ngrok and configure the remaining parts of your application.

Tests

You can run the tests locally with the following command. Before running, make sure the virtual environment is activated.

source venv/bin/activate
python3 -m pytest

Cloud deployment

Additionally to trying out this application locally, you can deploy it to a variety of host services. Here is a small selection of them.

Please be aware that some of these might charge you for the usage or might make the source code for this application visible to the public. When in doubt research the respective hosting service first.

Service
Heroku Deploy

Resources

  • The CodeExchange repository can be found here.

Contributing

This template is open source and welcomes contributions. All contributions are subject to our Code of Conduct.

License

MIT

Disclaimer

No warranty expressed or implied. Software is as is.

voice-javascript-sdk-quickstart-python's People

Contributors

bld010 avatar dprothero avatar jefflinwood avatar joliveros avatar jonedavis avatar rojastob avatar ryan-rowland avatar sarahcstringer avatar smendes avatar well1791 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

voice-javascript-sdk-quickstart-python's Issues

Unable to create record: No 'To' number is specified

If I make an outbound call using the docs way of doing it and enter a To phone number in the form input and use the following code I get the following error and traceback. Strangely, the outbound call goes through successfully to the typed in To number and the TwiML gets executed if the To number you call presses any key.

account_sid = 'XXXXXXXXXX'
auth_token = 'XXXXXXXXXXX'
client = Client(account_sid, auth_token)

if request.method == 'POST' and request.POST.get('To') is not None:
    call = client.calls.create(twiml='<Response><Say>Ahoy there!</Say></Response>',to=request.POST.get('To'),from_='+12345678909')
Traceback (most recent call last):
  File "/home/name/.local/share/virtualenvs/project_name/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/home/name/.local/share/virtualenvs/project_name/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/name/.local/share/virtualenvs/project_name/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/name/project_name/phone/views.py", line 148, in phone
    call = client.calls.create(twiml='<Response><Say>Ahoy there!</Say></Response>',to=request.POST.get('To'),from_='+12345678909')
  File "/home/name/.local/share/virtualenvs/project_name/lib/python3.8/site-packages/twilio/rest/api/v2010/account/call/__init__.py", line 146, in create
    payload = self._version.create(method='POST', uri=self._uri, data=data, )
  File "/home/name/.local/share/virtualenvs/project_name/lib/python3.8/site-packages/twilio/base/version.py", line 205, in create
    raise self.exception(method, uri, response, 'Unable to create record')
twilio.base.exceptions.TwilioRestException: 

405 METHOD NOT ALLOWED

I get a 200OK upon starting the device
but after entering a number and making the call, I get "We are sorry an application error has occurred, Goodbye!"
following is the screenshot of ngrok inspect
image
image

Add transfers for incoming and outgoing calls

It would be awesome if this github project had the feature of being able to type in another phone number or twilio client identity into the form and be able to click a transfer button to transfer the current incoming or outgoing call recipient to this new phone number.

There should be a fallback in case the number we are transferring to does not answer. In other words, we should be able to transfer again if the number we are transferring does not answer. Being stuck in a transferred to conference call and not being able to transfer again would get us stuck with nowhere to go.

Handle incoming calls that are busy or offline

If a browser user has a call in progress, and another outside caller tries calling up the browser user, the outside incoming caller just rings continuously and eventually gets disconnected.

Instead, the outside incoming caller should enter a queue and have hold music waiting for the browser user to finish their current call. There should also be a spoken message like "The phone number you tried calling is busy. Please hold".

If the browser user is not available at all meaning their Twilio.Device is not ready or offline the incoming caller should be able to leave a voicemail message to the browser user. The spoken message for this should be "The phone number you tried calling is not available. Please leave a message".

Another idea would be to forward this incoming caller to a different browser user who is available. But this is only if more than one browser user exists. Otherwise maybe forward the incoming call to some other phone number like your actual cell / landline phone number as a backup.

Key error

Whenever I call I get the following traceback in django from request.POST['phone']:

@csrf_exempt
def phone(request):
    form = PhoneForm()

    if request.method == 'POST':
        print(request.POST['phone']) #comes from javascript phone: phoneNumberInput.value
        form = PhoneForm(request.POST)
        if form.is_valid():
            print(form.cleaned_data.get("phone_number"))
            resp = VoiceResponse()
            resp.dial(str(request.POST['phone']), caller_id='+12345678909', action='/phone/', method='POST')
            return HttpResponse(str(resp), content_type='application/xml; charset=utf-8')


Internal Server Error: /phone/
Traceback (most recent call last):
  File "/home/name/.local/share/virtualenvs/project_name/lib/python3.8/site-packages/django/utils/datastructures.py", line 76, in __getitem__
    list_ = super().__getitem__(key)
KeyError: 'phone'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/name/.local/share/virtualenvs/project_name/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/home/name/.local/share/virtualenvs/project_name/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/name/.local/share/virtualenvs/project_name/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/name/video-membership-master/phone/views.py", line 78, in phone
    print(request.POST['phone']) #comes from javascript phone: phoneNumberInput.value
  File "/home/name/.local/share/virtualenvs/project_name/lib/python3.8/site-packages/django/utils/datastructures.py", line 78, in __getitem__
    raise MultiValueDictKeyError(key)
django.utils.datastructures.MultiValueDictKeyError: 'phone'

Move to Flask 2.x

This project no longer plays nicely with Flask 1.x. Bumping to current Flask version 2.1.3 resolves the issue.

make serve
. venv/bin/activate; \
        python3 app.py
Traceback (most recent call last):
  File "/Users/torndorff/Projects/git/voice-javascript-sdk-quickstart-python/app.py", line 8, in <module>
    from flask import Flask, Response, jsonify, redirect, request
  File "/Users/torndorff/Projects/git/voice-javascript-sdk-quickstart-python/venv/lib/python3.9/site-packages/flask/__init__.py", line 14, in <module>
    from jinja2 import escape
  File "/Users/torndorff/Projects/git/voice-javascript-sdk-quickstart-python/venv/lib/python3.9/site-packages/jinja2/__init__.py", line 12, in <module>
    from .environment import Environment
  File "/Users/torndorff/Projects/git/voice-javascript-sdk-quickstart-python/venv/lib/python3.9/site-packages/jinja2/environment.py", line 25, in <module>
    from .defaults import BLOCK_END_STRING
  File "/Users/torndorff/Projects/git/voice-javascript-sdk-quickstart-python/venv/lib/python3.9/site-packages/jinja2/defaults.py", line 3, in <module>
    from .filters import FILTERS as DEFAULT_FILTERS  # noqa: F401
  File "/Users/torndorff/Projects/git/voice-javascript-sdk-quickstart-python/venv/lib/python3.9/site-packages/jinja2/filters.py", line 13, in <module>
    from markupsafe import soft_unicode
ImportError: cannot import name 'soft_unicode' from 'markupsafe' (/Users/torndorff/Projects/git/voice-javascript-sdk-quickstart-python/venv/lib/python3.9/site-packages/markupsafe/__init__.py)
make: *** [serve] Error 1```

Add hold functionality for incoming and outgoing calls

Hold functionality is not part of the javascript SDK.

Mute functionality helps in certain situations, but it leaves the other party wondering if you are still on the line. If you leave the other party on mute too long, they will think you hung up on them and they will most likely hang up on you if they don't hear anything.

Adding hold music to let the other party know you are still on the line with them is useful when you have to be away from the phone for longer periods of time.

Another scenario would be to put a current call on hold and then accept another incoming call that comes in at the same time as the current call is in progress.

Show call status in the event log

When making an incoming call, answering the incoming caller from the browser, and then hanging up from the incoming caller's phone, there is no way for the browser user to know that the incoming caller hung up on them.

The browser console shows a DISCONNECT message from twilio.min.js properly for this situation and that would be nice to show in the event log too.

The incoming call controls also keeps showing "incoming call from +12345678909" after the incoming caller hangs up on the browser user. Then the browser user has to manually press the hangup button to prevent this message from showing - it still appears to the browser user that the incoming caller is still on the phone with them when they are not. This message should disappear automatically when an incoming caller hangs up on the browser user.

I setup a status_callback webhook URL and was able to get request.POST['CallStatus'] == 'completed' in the django server side code, but do not know how to display this call status to the browser user.

Make an equivalent django project

I would like to see this project written in django as opposed to flask. In fact, it is tough to do things in django when most of the twilio docs are in flask. The twilio django related docs for browser voice calls seem to be outdated with the newer javascript sdk. It is beyond frustrating as a django developer trying to use the latest twilio. The docs are all over the place compared to the github projects.

Call disconnects immediately

Hi,
I'm experimenting with this quickstart tutorial on Chrome (101.0.4951.64) for MacOS (12.3.1).
When I press "Call" it seems like there is an attempt to make a call but it disconnects immediately. There is no ring on the target phone that I try to call. I tried different phones and it behaves the same. I also tried another quickstart tutorial, for programmed voice, and it works well. So I believe my purchased number and the target number that I try to call are both fine.

The event log shows:

>  Requesting Access Token...
>  Got a token.
>  Initializing device
>  Twilio.Device Ready to make and receive calls!
>  Attempting to call <target number>...
>  Call disconnected.

Inspecting the JS console shows this:

Setting up VSP
twilio.min.js:1 Initializing preferred transport backoff using config:  {factor: 2, maxDelay: 1000, randomisationFactor: 0.4}
twilio.min.js:1 Initializing primary transport backoff using config:  {factor: 2, initialDelay: 100, maxDelay: 20000, randomisationFactor: 0.4}
twilio.min.js:1 WSTransport.open() called...
twilio.min.js:1 Attempting to connect...
twilio.min.js:1 Closing and cleaning up WebSocket...
twilio.min.js:1 No WebSocket to clean up.
twilio.min.js:1 WebSocket opened successfully.
twilio.min.js:1 Setting token and publishing listen
twilio.min.js:1 Stream is ready
twilio.min.js:1 signalingState is "have-local-offer"
twilio.min.js:1 dtlsTransportState is "new"
twilio.min.js:1 pc.iceGatheringState is "gathering"
twilio.min.js:1 ICE Candidate: {"candidate":"candidate:4131776327 1 udp 2122260223 192.168.68.115 55145 typ host generation 0 ufrag VD9m network-id 1 network-cost 10","sdpMid":"0","sdpMLineIndex":0}
twilio.min.js:1 ICE Candidate: {"candidate":"candidate:3099990967 1 tcp 1518280447 192.168.68.115 9 typ host tcptype active generation 0 ufrag VD9m network-id 1 network-cost 10","sdpMid":"0","sdpMLineIndex":0}
twilio.min.js:1 pc.iceGatheringState is "complete"
twilio.min.js:1 ICE Candidate: null
twilio.min.js:1 Received HANGUP from gateway
twilio.min.js:1 Received an error from the gateway: ConnectionError: ConnectionError (31005): Error sent from gateway in HANGUP
    at ConnectionError.TwilioError [as constructor] (twilio.min.js:1:98536)
    at new ConnectionError (twilio.min.js:1:84420)
    at PStream.Call._this._onHangup (twilio.min.js:1:21253)
    at emitOne (twilio.min.js:1:248707)
    at PStream.emit (twilio.min.js:1:250013)
    at PStream._handleTransportMessage (twilio.min.js:1:125763)
    at emitOne (twilio.min.js:1:248707)
    at WSTransport.emit (twilio.min.js:1:250013)
    at WebSocket.WSTransport._this._onSocketMessage (twilio.min.js:1:217569)
Log.error @ twilio.min.js:1
Call._this._onHangup @ twilio.min.js:1
emitOne @ twilio.min.js:1
emit @ twilio.min.js:1
PStream._handleTransportMessage @ twilio.min.js:1
emitOne @ twilio.min.js:1
emit @ twilio.min.js:1
WSTransport._this._onSocketMessage @ twilio.min.js:1
twilio.min.js:1 Disconnecting...
twilio.min.js:1 dtlsTransportState is "closed"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.