Mit Twilio Programmable Voice, Python und JavaScript Telefonanrufe vom Browser aus tätigen und empfangen

April 21, 2021
Autor:in:
Carlos Mucuho
Mitwirkende:r
Die von Twilio-Mitwirkenden geäußerten Meinungen sind ihre eigenen

In diesem Tutorial werden Sie eine Anwendung schreiben, die die programmierbare Sprach-API von Twilio verwendet, um Telefonanrufe über einen Webbrowser zu tätigen und zu empfangen. Sie werden auch eine Benutzeroberfläche implementieren, über die Sie Anrufe tätigen, empfangen und ablehnen.

Am Ende dieses Tutorials wird die Anwendung wie folgt aussehen:

Projekt-Demo

Voraussetzungen

Für dieses Tutorial benötigen Sie Folgendes:

  • Ein kostenloses oder kostenpflichtiges Twilio-Konto. Wenn Sie neu bei Twilio sind, erstellen Sie jetzt ein kostenloses Konto. Wenn Sie Ihr Konto über diesen Link erstellen und später auf ein kostenpflichtiges Konto upgraden, erhalten Sie eine Gutschrift in Höhe von 10 USD.
  • Eine Twilio-Telefonnummer, mit der Sie Anrufe tätigen und empfangen können. Besorgen Sie sich jetzt eine, wenn Sie noch keine haben.
  • Python 3.6 oder höher installiert
  • ngrok installiert. ngrok ist ein Reverse-Proxy-Dienst, der einen sicheren Tunnel von einem öffentlichen Endpunkt zu einem lokal ausgeführten Webdienst erstellt. Sie erstellen mit ngrok eine sichere URL, über die Twilio die Verbindung zu Ihrer Anwendung herstellen kann.
  • Ein Handy oder Telefon, mit dem Anrufe getätigt und empfangen werden können, um das Projekt zu testen.

Grundkonzept und Anwendungslogik

Ziel dieses Tutorials ist die Erstellung einer Webanwendung, mit der Sie im Browser Anrufe tätigen und empfangen können. Sie werden mit dem Flask-Framework die erforderlichen WebHooks implementieren und die Client-Anwendung bedienen.

Der Anwendungs-Client erstellt mit dem Twilio Client JS-SDK (twilio.js) ein Twilio-Gerät.

Ein Twilio-Gerät ist der Haupteinstiegspunkt für das Tätigen und Empfangen von Anrufen im Browser. Um eine Verbindung zwischen einem Twilio-Gerät und den Twilio-Servern herzustellen, müssen Sie im Anwendungsserver Zugriffstoken generieren.

Zugriffstoken sind kurzlebige Anmeldeinformationen, die sicher an clientseitige Anwendungen weitergegeben werden können, die Sie zur Authentifizierung von Twilio Client-SDKs wie Voice, Conversations, Sync und Video verwenden können. Mit einem Twilio-API-Schlüssel können Sie Zugriffstoken auf dem Server generieren.

Ein Twilio-API-Schlüssel ist eine Anmeldeinformation, mit der Sie auf die Twilio-API zugreifen können. Mit einem API-Schlüssel können Sie:

  • sich bei der API von Twilio authentifizieren
  • Zugriffstoken erstellen und widerrufen

Zugriffstoken gewähren dem Client Zugriff auf eine TwiML-Anwendung (TwiML-App). Twilio stützt sich auf eine TwiML-Anwendung innerhalb Ihres Kontos, um zu bestimmen, wie mit dem Server interagiert werden soll.

TwiML (die Twilio Markup Language) setzt sich aus Anweisungen zusammen, mit denen Sie Twilio wissen lassen, was zu tun ist, wenn Sie einen Anruf, eine SMS oder ein Fax erhalten.

Projektstruktur erstellen

In diesem Abschnitt erstellen Sie das Projektverzeichnis. Innerhalb dieses Verzeichnisses legen Sie die Standardverzeichnisse für eine Flask-Anwendung an. Danach werden Sie eine virtuelle Umgebung erstellen und aktivieren. Abschließend installieren Sie die Python-Pakete, die für die Erstellung dieser Webanwendung benötigt werden.

Öffnen Sie ein Terminalfenster und geben Sie die folgenden Befehle ein:

$ git clone git@github.com:CSFM93/tutorial-twilio-in-browser-calling-start.git twilio-in-browser-calls
$ cd twilio-in-browser-calls

Hier haben Sie ein Starterprojekt geklont, das für dieses Tutorial erstellt wurde, und ihm den Namen twilio-in-browser-calls gegeben. Anschließend sind Sie in das Projektverzeichnis gewechselt. Dieses Projekt enthält Code aus gängigen Textbausteinen, den Sie zum Erstellen Ihrer Anwendung verwenden werden.

Sie finden darin die folgenden Standardverzeichnisse für eine Flask-Anwendung:

  • static: Hier werden alle statischen Dateien gespeichert.
  • templates: Hier werden die Vorlagen gespeichert.

Das Unterverzeichnis static hat folgende Inhalte:

  • css: Hier werden alle CSS-Dateien gespeichert. In diesem Unterverzeichnis gibt es eine Datei mit dem Namen style.css. Diese Datei ist für die Gestaltung der Benutzeroberfläche Ihrer Anwendung zuständig.
  • images: Hier werden alle Bilder gespeichert. In diesem Unterverzeichnis gibt es eine Datei mit dem Namen user.png, die Sie in der Benutzeroberfläche Ihrer Anwendung anzeigen werden.
  • js:  Hier werden alle Javascript-Dateien gespeichert.  In diesem Verzeichnis gibt es eine Datei mit dem Namen modals.js. Diese Datei enthält den Code zur Verwaltung des im Verzeichnis templates gespeicherten Dialogfelds.

Das Unterverzeichnis templates enthält drei Dateien: call_in_progress_modal.html, dial_modal.html und incoming_call_modal.html.

Die Datei call_in_progress_modal.html enthält den HTML-Code, der ein Dialogfeld implementiert, das während eines Anrufs angezeigt wird. Dieses Dialogfeld zeigt die Dauer des laufenden Anrufs, die Nummer, die Sie anrufen, und eine Schaltfläche mit einem roten Telefonsymbol an, über die Sie den Anruf beenden können. So sieht das Dialogfeld aus:

 

Seite mit laufendem Anruf

Die Datei dial_modal.html enthält den HTML-Code zur Implementierung eines Dialogfelds, das angezeigt wird, wenn Sie eine Telefonnummer wählen möchten. Dieses Dialogfeld zeigt eine numerische Tastatur und eine Schaltfläche mit einem grünen Telefonsymbol. Das sieht so aus:

Seite zum Wählen einer Nummer

Die Datei incoming_call_modal.html enthält den HTML-Code für eine Vorlage, die ein Dialogfeld implementiert, das nur dann angezeigt wird, wenn Sie einen Anruf erhalten. Dieses Dialogfeld zeigt die Nummer, die Sie anruft, sowie zwei Schaltflächen: eine mit einem grünen Telefonsymbol und eine mit einem roten Telefonsymbol. Mit der ersten Schaltfläche können Sie einen eingehenden Anruf annehmen, mit der zweiten ablehnen.

Seite für eingehende Anrufe

Erstellen Sie eine virtuelle Umgebung im Arbeitsverzeichnis und aktivieren Sie sie. Führen Sie bei einem Unix- oder Mac-Betriebssystem dafür die folgenden Befehle aus:

$ python3 -m venv venv
$ source venv/bin/activate

Wenn Sie diesem Tutorial unter Windows folgen, führen Sie stattdessen die folgenden Befehle aus:

$ python -m venv venv
$ venv\Scripts\activate

Nachdem Sie nun die virtuelle Umgebung erstellt und aktiviert haben, können Sie die Bibliotheken installieren, die Sie für die Erstellung Ihrer Anwendung benötigen:

$ pip install twilio flask python-dotenv

Im obigen Befehl haben Sie pip, den Python-Paket-Installer verwendet, um die folgenden Pakete zu installieren, die Sie in diesem Projekt verwenden werden:

  • Twilio, ein Python-Paket für die Kommunikation mit der Twilio-API.
  • Flask, ein Python-Mikro-Framework zur Erstellung von Webanwendungen. Damit erstellen Sie einen WebHook, um mit Twilio zu interagieren und die Client-Benutzeroberfläche zum Tätigen und Empfangen von Anrufen zu erstellen.
  • Python-dotenv, eine Bibliothek, die Schlüssel-Wert-Paare aus einer Datei liest und sie als Umgebungsvariablen hinzufügt. Mit diesem Modul rufen Sie die Twilio-Anmeldeinformationen ab, die in einer .env-Konfigurationsdatei gespeichert sind.

Zu Ihrer Information: Zum Zeitpunkt der Veröffentlichung dieses Tutorials waren dies die getesteten Versionen der genannten Pakete und der Pakete, von denen sie abhängig sind:

certifi==2020.12.5
chardet==4.0.0
click==7.1.2
Flask==1.1.2
idna==2.10
itsdangerous==1.1.0
Jinja2==2.11.3
MarkupSafe==1.1.1
PyJWT==1.7.1
python-dotenv==0.17.0
pytz==2021.1
requests==2.25.1
six==1.15.0
twilio==6.55.0
urllib3==1.26.4
Werkzeug==1.0.1

Neben den oben erwähnten Python-Paketen werden Sie die folgenden Frontend-Bibliotheken verwenden:

  • Bootstrap, ein leistungsfähiges Frontend-Framework für die Erstellung moderner Websites.
  • Twilio Client JS-SDK(twilio.js), eine Bibliothek, mit der Sie über einen Webbrowser Sprachanrufe tätigen können.
  • JQuery, eine schnelle, kleine und funktionsreiche JavaScript-Bibliothek, mit der Dinge wie Traversal und Manipulation von HTML-Dokumenten, Ereignisverarbeitung, Animation und Ajax viel einfacher sind. Sie werden damit einige DOM-Manipulationen und Ereignisverarbeitungen durchführen.
  • Font Awesome, ein beliebtes, auf CSS basierendes Toolkit für Symbole und Schriftarten. Sie werden einige der von ihnen entworfenen Symbole im Anwendungsclient verwenden.

TwiML-Anwendung erstellen

In diesem Abschnitt erstellen Sie mit der Twilio-Konsole eine „TwiML-App“. Dort werden Sie später die URL des Webhooks speichern, den Sie entwickeln werden.

Öffnen Sie ein neues Browserfenster und navigieren Sie zu Twilio account Console > Voice > TwiML > TwiML Apps (Twilio-Kontokonsole > Voice > TwiML > TwiML-Apps). Klicken Sie auf die Schaltfläche „Create new TwiML App“ (Neue TwiML-App erstellen) oder auf das rote „+“-Symbol, wenn Sie bereits andere TwiML-Apps haben.

 

TwiML-Apps

Geben Sie in das Feld „Friendly Name“ (Anzeigename) den Namen für Ihre TwiML-App ein, z. B. in-browser calls. Lassen Sie die anderen Felder vorerst leer. Klicken Sie auf die Schaltfläche „Create“ (Erstellen), um die TwiML-Anwendung zu erstellen.

Seite der TwiML-App

Sie werden zurück zum Dashboard der TwiML-Apps geleitet. Klicken Sie auf die TwiML-App, die Sie eben erstellt haben. Wählen Sie auf der Seite für diese App den SID-Wert aus und kopieren Sie ihn in die Zwischenablage.

Seite der TwiML-App

Erstellen Sie im Stammverzeichnis des Projekts eine Datei mit dem Namen .env und geben Sie darin Folgendes ein:

TWIML_APP_SID="paste your TwiML app SID here"

Twilio-API-Schlüssel erstellen

Im nächsten Schritt erstellen Sie einen Twilio-API-Schlüssel für die Voice API. Mit dem API-Schlüssel werden Zugriffstoken generiert, mit denen das im Browser ausgeführte Frontend Aufrufe an Twilio-APIs tätigen kann.

Navigieren Sie in Ihrem Browser zu Twilio console > Voice > Settings > API Keys (Twilio-Konsole > Voice > Einstellungen > API-Schlüssel). Klicken Sie auf die Schaltfläche „Create new API Key“ (Neuen API-Schlüssel erstellen) oder auf das rote „+“-Symbol, wenn Sie bereits andere API-Schlüssel haben.

Twilio-API-Schlüssel

Geben Sie in das Feld „Friendly Name“ (Anzeigename) den Namen für Ihren API-Schlüssel ein, z. B. in-browser calls. Lassen Sie „Key Type“ (Schlüsseltyp) auf „Standard“. Klicken Sie auf die Schaltfläche „Create API Key“ (API-Schlüssel erstellen).

Neuer API-Schlüssel

Sie werden zu einer Seite weitergeleitet, die Informationen über Ihren neuen API-Schlüssel enthält. Kopieren Sie die Werte von „SID“ und „Secret“ (Geheimer Schlüssel) und fügen Sie sie in Ihre .env-Datei als TWILIO_API_KEY_SID und TWILIO_API_KEY_SECRET ein. Ihre .env-Datei sollte wie folgt aussehen:

TWIML_APP_SID="paste your TwiML app SID here"
TWILIO_API_KEY_SID="paste your API key SID here"
TWILIO_API_KEY_SECRET="paste your API key secret here"

Aktivieren Sie das Kontrollkästchen „Got it!“ (Erledigt) und klicken Sie auf die Schaltfläche „Done“ (Fertigstellen).

Erstellter API-Schlüssel

Gehen Sie nun zur Startseite der Twilio-Konsole und kopieren Sie die SID Ihres Twilio-Kontos wie folgt in die .env-Datei:

TWIML_APP_SID="paste your TwiML app SID here"
TWILIO_API_KEY_SID="paste your API key SID here"
TWILIO_API_KEY_SECRET="paste your API key secret here"
TWILIO_ACCOUNT_SID="paste your Twilio Account SID here"

Gehen Sie dann zu Twilio account console > Phone Numbers > Manage Numbers > Active Numbers (Twilio-Kontokonsole > Telefonnummern > Nummern verwalten > Aktive Nummern), wählen Sie die Nummer aus, die Sie für dieses Tutorial erworben haben, und Sie werden zu einer Seite weitergeleitet, auf der Sie diese Nummer konfigurieren können. Suchen Sie das Feld „Phone Number“ (Telefonnummer), kopieren Sie die Nummer unter diesem Feld und fügen Sie sie in die .env-Datei als TWILIO_NUMBER ein. Entfernen Sie alle Leerzeichen zwischen den Ziffern, aber lassen Sie das Pluszeichen vorn stehen, damit die Nummer das E.164-Format hat.

Twilio-Telefonnummer

Ihre .env-Datei sollte nach dem Hinzufügen der Telefonnummer wie folgt aussehen:

TWIML_APP_SID="paste your TwiML app SID here"
TWILIO_API_KEY_SID="paste your API key SID here"
TWILIO_API_KEY_SECRET="paste your API key secret here"
TWILIO_ACCOUNT_SID="paste your Twilio Account SID here"
TWILIO_NUMBER="paste your Twilio phone number here"

Flask-Anwendung erstellen

In diesem Abschnitt erstellen Sie die Logik der Flask-Anwendung, die die unterstützenden Funktionen zum Tätigen und Empfangen von Telefonanrufen für das Frontend bereitstellt.

Anwendungsserver erstellen

In diesem Unterabschnitt erstellen Sie die Endpunkte, die zum Tätigen und Empfangen von Telefonanrufen benötigt werden. Sie müssen die folgenden Endpunkte erstellen:

  • /: Dieser Endpunkt bedient die Benutzeroberfläche der Anwendung (Client).
  • /token: Dieser Endpunkt erzeugt die Zugriffstoken und gibt sie an den Client zurück.
  • /handle_calls: Dieser Endpunkt generiert die TwiML-Anweisungen zum Tätigen und Empfangen von Telefonanrufen.

Erstellen Sie im Stammverzeichnis Ihres Projekts eine Datei mit dem Namen main.py. Öffnen Sie die Datei mit Ihrem bevorzugten Texteditor und fügen Sie den folgenden Code hinzu:

from flask import Flask, render_template, jsonify
from flask import request
 
from twilio.jwt.access_token import AccessToken
from twilio.jwt.access_token.grants import VoiceGrant
from twilio.twiml.voice_response import VoiceResponse, Dial
 
from dotenv import load_dotenv
import os
import pprint as p

Hier wurden alle Pakete importiert, die Sie für die Erstellung der Serveranwendung benötigen:

  • Mit flask werden die Endpunkte der Anwendung definiert.
  • Das twilio-Paket ermöglicht die Interaktion mit der Twilio-API, sodass Sie über das Twilio-Gerät, das auf dem Client erstellt wird, Anrufe tätigen und empfangen können.
  • load_dotenv wird verwendet, um Twilio-Anmeldeinformationen für das Twilio-Konto aus der Datei .env zu importieren.
  • pprint wird verwendet, um die empfangenen Daten zu formatieren und zu drucken, wenn Twilio eine Anfrage an den Endpunkt /handle_calls sendet, um über einen Anruf zu informieren.
  • os dient zusammen mit load_dotenv zum Abrufen der in der .env-Datei gespeicherten Anmeldeinformationen.

Fügen Sie den folgenden Code am Ende der Datei main.py hinzu:

load_dotenv()

account_sid = os.environ['TWILIO_ACCOUNT_SID']
api_key = os.environ['TWILIO_API_KEY_SID']
api_key_secret = os.environ['TWILIO_API_KEY_SECRET']
twiml_app_sid = os.environ['TWIML_APP_SID']
twilio_number = os.environ['TWILIO_NUMBER']

app = Flask(__name__)


@app.route('/')
def home():
    return render_template(
        'home.html',
        title="In browser calls",
    )

Die Anwendung importiert die ersten in der .env-Datei gespeicherten Umgebungsvariablen durch einen Aufruf von load_dotenv(). Auf diese Weise können Sie die fünf für diese Anwendung benötigten Konfigurationsvariablen abrufen.

Erstellen Sie dann eine Flask-Anwendungsinstanz in einer Variablen namens app und damit den Endpunkt / der Anwendung. Diese Route bedient eine Vorlage namens home.html, die Sie später erstellen werden.

Fügen Sie den folgenden Code unter der Route / hinzu:

@app.route('/token', methods=['GET'])
def get_token():
    identity = twilio_number
    outgoing_application_sid = twiml_app_sid

    access_token = AccessToken(account_sid, api_key,
                               api_key_secret, identity=identity)

    voice_grant = VoiceGrant(
        outgoing_application_sid=outgoing_application_sid,
        incoming_allow=True,
    )
    access_token.add_grant(voice_grant)

    response = jsonify(
        {'token': access_token.to_jwt().decode(), 'identity': identity})

    return response

Dadurch wird der Endpunkt /token hinzugefügt, der vom Client zum Anfordern eines Zugriffstokens aufgerufen wird.

Bei Auslösung dieses Endpunkts wird eine Variable mit dem Namen identity erstellt und Ihrer Twilio-Nummer zugewiesen. Eine Identität ist für Nutzer:innen eindeutig und kann auf mehreren Geräten gleichzeitig angemeldet werden. Auf einem Anwendungsserver für mehrere Nutzer:innen müssen Sie anhand der Token-Anfrage, die an Sie gesendet wird, entscheiden, wer die Person ist und was sie tun darf. Über Ihr bestehendes Anmeldesystem oder Ihren Identitätsanbieter (z. B. Sitzungscookies, API-Token oder anderer Mechanismus, der zur Sicherung Ihrer API-Anfragen verwendet wird) würden wir Nutzer:innen identifizieren. In diesem Tutorial sind Sie jedoch der einzige Nutzer. Daher müssen Sie nicht mit mehreren Identitäten arbeiten. Die Twilio-Nummer, die Sie für dieses Tutorial erworben haben, ist dafür gut geeignet.

Anschließend erstellen Sie mit account_sid, api_key, api_key_secret und identity ein Zugriffstoken. Das Token muss mit „Grants“ versehen werden, die festlegen, was der Client, der das Token präsentiert, tun darf. Für diese Anwendung erstellen Sie ein Voice Grant-Objekt, das mit der sid der zuvor erstellten TwiML-App konfiguriert wird.

Zur Vervollständigung des Endpunkts geben Sie access_token und identity im JSON-Format an den Client zurück.

Fügen Sie den folgenden Code unter der Route /token hinzu:

@app.route('/handle_calls', methods=['POST'])
def call():
    p.pprint(request.form)
    response = VoiceResponse()
    dial = Dial(callerId=twilio_number)

    if 'To' in request.form and request.form['To'] != twilio_number:
        print('outbound call')
        dial.number(request.form['To'])
        return str(response.append(dial))

    return ''


if __name__ == "__main__":
    app.run(host='0.0.0.0', port=3000, debug=True)

In diesem Abschnitt wird ein Endpunkt mit dem Namen /handle_calls hinzugefügt. Der Endpunkt wird von Twilio immer dann aufgerufen, wenn Sie einen Telefonanruf tätigen oder empfangen.

Wenn dieser Endpunkt ausgelöst wird, drucken Sie mit pprint den Inhalt von request.form. Dann erstellen Sie ein TwiML-Antwortobjekt und ein TwiML-Wählobjekt. Im Objekt dial legen Sie für callerId die Twilio-Nummer fest, die Sie für dieses Tutorial erworben haben. Wenn Sie also eine Telefonnummer mit dieser Anwendung anrufen, wird auf dem Empfängertelefon die Nummer anstelle von anonymous angezeigt.

Danach überprüfen Sie mit bedingter Logik, ob das Objekt request.form die Eigenschaft To hat und ob der Wert dieser Eigenschaft nicht mit Ihrer twilio_number übereinstimmt. Mit diesem ersten Test wird sichergestellt, ob beim Aufruf des Endpunkts ein Anruf getätigt (nicht empfangen) wird.

Sobald Sie sicher sind, dass es sich um eine Anfrage zum Tätigen eines Anrufs handelt, legen Sie die zu wählende Nummer auf den Wert in request.form['To'] fest, hängen das Objekt dial an das Objekt response an und geben das Objekt response als String an Twilio zurück, der diese Anweisungen ausführt und die angeforderte Nummer wählt.

Der untere Teil des Skripts ist eine Standardbedingung, die den Flask-Entwicklungsserver auf Port 3000 ausführt, wenn das Skript von der Befehlszeile aus aufgerufen wird.

Anwendungsclient erstellen

In diesem Unterabschnitt erstellen Sie das Frontend, mit dem Sie Telefonanrufe im Browser tätigen und empfangen können.

Startseite erstellen

Erstellen Sie eine Datei mit dem Namen home.html im Verzeichnis templates. Öffnen Sie die Datei und fügen Sie den folgenden Code hinzu:

<!DOCTYPE html>
<html>
<head>
    <title>In browser calls</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" />
    <link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
    <div class="container">
        <!-- log output -->
        <div class="card text-center log-container">
            <h3>Device log</h3>
            <div id="log"></div>
            <div class="btn-container">
                <button type="button" id="btnOpenNumberPad" class="btn btn-default btn-circle btn-lg">
                    <i class="fa fa-phone fa-flip-horizontal " aria-hidden="true" style="color: green;"></i>
                </button>
            </div>
        </div>

        <!-- Modal dial -->
        {% include 'dial_modal.html' %}

        <!-- Modal call in progress -->
        {% include 'call_in_progress_modal.html' %}

        <!-- Modal incoming call -->
        {% include 'incoming_call_modal.html' %}


        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <script type="text/javascript" src="https://media.twiliocdn.com/sdk/js/client/v1.8/twilio.min.js"></script>
        <script type="text/javascript" src="/static/js/main.js"></script>
        <script type="text/javascript" src="/static/js/modals.js" defer></script>
</body>

</html>

Diese Vorlage implementiert eine Seite, die eine Konsole anzeigt. Hier können Sie den Status des Twilio-Geräts überwachen, das Sie bald mit JavaScript erstellen werden. Diese Vorlage enthält die Vorlagen call_in_progress_modal.html, dial_modal.html und incoming_call_modal.html, die mit den Bausteinen dieses Projekts zur Verfügung gestellt wurden. Auf dieser Seite wird auch eine Schaltfläche mit einem Telefonsymbol angezeigt. Wenn Sie auf die Schaltfläche klicken, öffnet sich ein Dialogfeld, in das Sie die Nummer eingeben, die Sie anrufen möchten.

Neben den Dateien Bootstrap, jQuery, FontAwesome und twilio.js sind auch die folgenden Dateien in dieser Vorlage enthalten:

  • style.css: Diese Datei enthält einige der CSS für die Gestaltung Ihrer Anwendung.
  • main.js: Diese Javascript-Datei enthält den Code zum Erstellen eines Twilio-Geräts und zum Verbinden mit der TwiML-Anwendung.
  • modals.js: Diese Javascript-Datei enthält den Code für die Verwaltung des Dialogfelds in Ihrer Anwendung.

Die Dateien style.css und modals.js befinden sich im Standard-Repository des Projekts. Die Datei main.js werden Sie im nächsten Unterabschnitt erstellen.

Twilio-Gerät erstellen

Erstellen Sie eine Datei mit dem Namen main.js im Verzeichnis static/js. Öffnen Sie die Datei und fügen Sie den folgenden Code hinzu:

$(function () {
    var device;

    log("Requesting Access Token...");
    // Using a relative link to access the Voice Token function
    $.getJSON("./token")
        .then(function (data) {
            log("Got a token.");
            console.log("Token: " + data.token);

            // Setup Twilio.Device
            device = new Twilio.Device(data.token, {
                // Set Opus as our preferred codec. Opus generally performs better, requiring less bandwidth and
                // providing better audio quality in restrained network conditions. Opus will be default in 2.0.
                codecPreferences: ["opus", "pcmu"],
                // Use fake DTMF tones client-side. Real tones are still sent to the other end of the call,
                // but the client-side DTMF tones are fake. This prevents the local mic capturing the DTMF tone
                // a second time and sending the tone twice. This will be default in 2.0.
                fakeLocalDTMF: true,
                // Use `enableRingingState` to enable the device to emit the `ringing`
                // state. The TwiML backend also needs to have the attribute
                // `answerOnBridge` also set to true in the `Dial` verb. This option
                // changes the behavior of the SDK to consider a call `ringing` starting
                // from the connection to the TwiML backend to when the recipient of
                // the `Dial` verb answers.
                enableRingingState: true,
                debug: true,
            });

            device.on("ready", function (device) {
                log("Twilio.Device Ready!");
            });

            device.on("error", function (error) {
                log("Twilio.Device Error: " + error.message);
            });

            device.on("connect", function (conn) {
                log('Successfully established call ! ');
                $('#modal-call-in-progress').modal('show')
            });

            device.on("disconnect", function (conn) {
                log("Call ended.");
                $('.modal').modal('hide')
            });

        })
        .catch(function (err) {
            console.log(err);
            log("Could not get a token from server!");
        });

    // Bind button to make call
    $('#btnDial').bind('click', function () {
        $('#modal-dial').modal('hide')

        // get the phone number to connect the call to
        var params = {
            To: document.getElementById("phoneNumber").value
        };

        // output destination number
        $("#txtPhoneNumber").text(params.To)
        

        console.log("Calling " + params.To + "...");
        if (device) {
            var outgoingConnection = device.connect(params);
            outgoingConnection.on("ringing", function () {
                log("Ringing...");
            });
        }

    })

    // Bind button to hangup call

    $('.btnHangUp').bind('click', function () {
        $('.modal').modal('hide')
        log("Hanging up...");
        if (device) {
            device.disconnectAll();
        }
    })

    // Activity log
    function log(message) {
        var logDiv = document.getElementById("log");
        logDiv.innerHTML += "<p>&gt;&nbsp;" + message + "</p>";
        logDiv.scrollTop = logDiv.scrollHeight;
    }

});

Hier erstellen Sie das Twilio-Gerät, mit dem Sie Telefonanrufe im Browser tätigen und empfangen können.

Zunächst verwenden Sie die von jQuery bereitgestellte Funktion getJSON(), um eine GET-Anforderung an den Endpunkt /token auf dem Anwendungsserver zu senden und ein Zugriffstoken abzurufen. Nachdem Sie das Token abgerufen haben, verwenden Sie twilio.js und das Token, um ein Twilio-Gerät zu erstellen und es mit der TwiML-Anwendung zu verbinden.

Nachdem Sie das Twilio-Gerät erstellt haben, fügen Sie diesem Gerät einige Ereignis-Listener und etwas Code hinzu, mit dem Sie über die Benutzeroberfläche mit dem Gerät interagieren können.

Ausgehende Anrufe tätigen

In diesem Abschnitt werden Sie mit Ihrer Anwendung ausgehende Anrufe tätigen. Aber bevor Sie das tun können, müssen Sie die Anwendung ausführen, ngrok einrichten und die TwiML-App konfigurieren.

Öffnen Sie ein zweites Terminalfenster im Projektverzeichnis, aktivieren Sie die virtuelle Python-Umgebung und starten Sie die Anwendung, indem Sie den folgenden Befehl ausführen:

$ python main.py
``

Open another terminal window and start `ngrok` on it:

Nachdem Sie den obigen Befehl ausgeführt haben, sollten Sie in etwa Folgendes sehen:

Ngrok-Ausgabe

Kopieren Sie die https-ngrok-URL in die Zwischenablage. Gehen Sie dann zu Ihrem Dashboard unter Twilio account Console > Voice> TwiML > TwiML Apps (TwiML-Kontokonsole > Voice > TwiML > TwiML-Apps) und wählen Sie die für dieses Tutorial erstellte TwiML-App aus.

Voice WebHook in der TwiML-App konfigurieren

Suchen Sie den Abschnitt „Voice“ in der Konfiguration der TwiML-App. Fügen Sie im Feld „Request URL“ (URL anfordern) die https://-URL ein, die von ngrok bereitgestellt wurde, gefolgt von /handle_calls und klicken Sie auf die Schaltfläche „Save“ (Speichern). Dadurch wird ein WebHook erstellt, der Ihre Anwendung mit der TwiML-App verbindet.

In diesem Beispiel ist die ngrok-URL https://48dcc810632b.ngrok.io/handle_calls. Der erste Teil der URL wird bei jedem Start von ngrok anders sein.

Schließen Sie nun ein Headset mit Mikrofon an Ihren Computer an, öffnen Sie danach Ihren Browser und geben Sie http://localhost:3000/ in die Adresszeile ein. Sie sollten in etwa Folgendes sehen:

 

Anwendungsseite zu Beginn

Sobald die Meldung Twilio.Device Ready! angezeigt wird, funktioniert Ihr Twilio-Gerät wie vorgesehen. Klicken Sie auf die Schaltfläche mit dem grünen Telefonsymbol. Sie sollten das Nummernfeld sehen:

Nummernfeld

Geben Sie die Nummer, die Sie anrufen möchten, über das Nummernfeld ein oder tippen Sie sie einfach mit der Tastatur in das Eingabefeld über dem Block. Klicken Sie anschließend auf den grünen Telefonhörer, um den Anruf zu tätigen.

Sobald Sie auf diese Schaltfläche klicken, fragt Ihr Browser um Erlaubnis, das Mikrofon zu verwenden. Erteilen Sie diese Erlaubnis. Sobald die Nummer, die Sie anrufen, Ihren Anruf entgegennimmt, wird das Dialogfeld „Laufender Anruf“ angezeigt:

Seite mit laufendem Anruf

Gehen Sie zum Terminal, auf dem die Flask-Anwendung ausgeführt wird. Die Anfragedaten, die Twilio an den Endpunkt /handle_calls sendet, sehen in etwa wie folgt aus:

{'AccountSid': 'ACe6c069eb8828c025719e6bbb20d63c75',
 'ApiVersion': '2010-04-01',
 'ApplicationSid': 'AP596a0557d23b118259f2cf355fb3693a',
 'CallSid': 'CAc8356bdd69dec58624588f7d578e5668',
 'CallStatus': 'ringing',
 'Called': '',
 'Caller': 'client:+1xxxxxxxxxx',
 'Direction': 'inbound',
 'From': 'client:+1xxxxxxxxxx',
 'To': '+1xxxxxxxxxx'}
outbound call

Da der Wert der Eigenschaft To (die Nummer, die Sie angerufen haben) nicht mit der Twilio-Nummer übereinstimmt, wurde der Code innerhalb der if-Anweisung im Endpunkt handle_calls ausgeführt.

Eingehende Telefonanrufe annehmen

Im vorherigen Abschnitt konnten Sie mit Ihrer Anwendung Anrufe tätigen, aber bisher keine Anrufe empfangen. Dafür müssen Sie zusätzlichen Code in main.py, main.js und home.html einfügen und die Nummer, die Sie für dieses Tutorial gekauft haben, in der Twilio-Konsole so konfigurieren, dass sie Anrufe empfangen kann.

Gehen Sie zurück zur Datei main.py und ersetzen Sie den Code im Endpunkt /handle_calls durch folgenden Code:

@app.route('/handle_calls', methods=['POST'])
def call():
    p.pprint(request.form)
    response = VoiceResponse()
    dial = Dial(callerId=twilio_number)

    if 'To' in request.form and request.form['To'] != twilio_number:
        print('outbound call')
        dial.number(request.form['To'])
    else:
        print('incoming call')
        caller = request.form['Caller']
        dial = Dial(callerId=caller)
        dial.client(twilio_number)

    return str(response.append(dial))

Hier haben Sie die Anweisung else zum Endpunkt /handle_calls hinzugefügt. Der Code in diesem Teil wird ausgeführt, wenn die Nummer, unter der der Anruf eingeht, die Nummer ist, die Sie für dieses Tutorial gekauft haben. Das heißt, Sie haben einen eingehenden Anruf.

Legen Sie die callerId im TwiML-Wählobjekt auf den Wert der Eigenschaft Caller in request.form fest. Wie der Name vermuten lässt, ist Caller die Nummer, die Ihre Twilio-Nummer anruft. So können Sie in der Benutzeroberfläche Ihrer Anwendung sehen, wer anruft. Legen Sie außerdem client im Wählobjekt auf den Wert identity fest, den Sie bei der Erstellung eines Zugriffstokens im Endpunkt /token verwendet haben.

Um den Ablauf des eingehenden Anrufs abzuschließen, hängen Sie das Wählobjekt an das TwiML-Antwortobjekt an und geben dieses Antwortobjekt als String zurück.

Gehen Sie zurück zur Datei main.js und fügen Sie den folgenden Code unter dem Listener device.on(‘disconnect') hinzu:

device.on("incoming", function (conn) {
    console.log(conn.parameters)
    log("Incoming connection from " + conn.parameters.From);
    $("#callerNumber").text(conn.parameters.From)
    $("#txtPhoneNumber").text(conn.parameters.From)

    $('#modal-incomming-call').modal('show')

    $('.btnReject').bind('click', function () {
        $('.modal').modal('hide')
        log("Rejected call ...");
        conn.reject();
    })

    $('.btnAcceptCall').bind('click', function () {
        $('.modal').modal('hide')
        log("Accepted call ...");
        conn.accept();
    })

});

Hier haben Sie einen Ereignis-Listener hinzugefügt, mit dem Ihr Twilio-Gerät eingehende Anrufe überwachen und das Dialogfeld für eingehende Anrufe anzeigen kann, sobald es einen solchen erkennt.

Gehen Sie zurück zum Dashboard unter Twilio console > Phone Numbers > Manage Numbers > Active Numbers (Twilio-Konsole > Telefonnummern > Nummern verwalten > Aktive Nummern).

Gehen Sie unter Telefonnummernkonfiguration zum Abschnitt „Voice & Fax“ und wählen Sie „TwiML App“ im Feld „Configure With“ (Konfigurieren mit) aus. Wählen Sie anschließend im Feld „TwiML App“ den Namen der TwiML-App aus, die Sie für dieses Tutorial erstellt haben. Auf diese Weise wird die Twilio-Nummer, die Sie für dieses Tutorial erworben haben, mit der von Ihnen erstellten TwiML-App verbunden. Immer, wenn diese Nummer einen Telefonanruf erhält, werden die WebHook-URL und andere Konfigurationen in der TwiML-App abgerufen und zur Beantwortung des Anrufs verwendet.  Hier wird eine POST-Anfrage an https://48dcc810632b.ngrok.io/handle_calls gesendet, die die Nummer des/der Anrufenden und andere nützliche Informationen enthält.

Gehen Sie zurück zu Ihrem Browser und navigieren Sie zu http://localhost:3000/. Warten Sie, bis die Meldung Twilio.Device Ready! auf der Seite angezeigt wird. Rufen Sie dann mit einem entsprechenden Gerät die Twilio-Nummer an, die Sie für dieses Tutorial erworben haben. Sobald es klingelt, sollten Sie das Dialogfeld für eingehende Anrufe sehen:

 

Seite für eingehende Anrufe

Drücken Sie die Taste mit dem grünen Symbol, um den Anruf anzunehmen, oder die Taste mit dem roten Telefonsymbol, um ihn abzulehnen.

Gehen Sie zum Terminal, auf dem die Flask-Anwendung ausgeführt wird. Die Anfragedaten, die Twilio an den Endpunkt /handle_calls sendet, sehen in etwa wie folgt aus:

{'AccountSid': 'ACe6c069eb8828c025719e6bbb20d63c75',
 'ApiVersion': '2010-04-01',
 'ApplicationSid': 'AP596a0557d23b118259f2cf355fb3693a',
 'CallSid': 'CAf0eb0489e54978471b96dd258dff4de9',
 'CallStatus': 'ringing',
 'Called': '+17146134152',
 'CalledCity': 'SILVERADO',
 'CalledCountry': 'US',
 'CalledState': 'CA',
 'CalledZip': '92676',
 'Caller': '+17205752613',
 'CallerCity': '',
 'CallerCountry': 'US',
 'CallerState': 'CO',
 'CallerZip': '',
 'Direction': 'inbound',
 'From': '+17205752613',
 'FromCity': '',
 'FromCountry': 'US',
 'FromState': 'CO',
 'FromZip': '',
 'To': '+17146134152',
 'ToCity': 'SILVERADO',
 'ToCountry': 'US',
 'ToState': 'CA',
 'ToZip': '92676'}
incoming call

 

Fazit

In diesem Tutorial haben Sie gelernt, wie Sie mit der Twilio Voice API Telefonanrufe im Browser tätigen und empfangen. Sie wissen jetzt außerdem, wie Sie mit dem Flask-Framework den Anwendungsclient erstellen, über den Sie mit einem Twilio-Gerät interagieren können, das mit dem Twilio Client JS-SDK erstellt wurde.

Der Code für die gesamte Anwendung ist im folgenden Repository verfügbar: https://github.com/CSFM93/twilio-in-browser-calls.

Carlos Mucuho ist ein mosambikanischer Geologe, der Gefallen am Entwickeln gefunden hat und Ideen gern mit Programmierung in die Realität umsetzt. https://github.com/CSFM93