
Teilen Sie:
Ben ist ein Entwickler im zweiten Beruf, der zuvor ein Jahrzehnt in den Bereichen Erwachsenenbildung, Community-Organisation und Non-Profit-Management tätig war. Er arbeitete als Anwalt für Entwickler bei Vonage. Er schreibt regelmäßig über die Überschneidung von Gemeindeentwicklung und Technologie. Ursprünglich aus Südkalifornien stammend und lange Zeit in New York City ansässig, wohnt Ben jetzt in der Nähe von Tel Aviv, Israel.
Aufzeichnung eines Anrufs in Ruby mit Vonage Voice API WebSockets
Lesedauer: 9 Minuten
Die Vonage Voice API WebSockets Funktion hat kürzlich den Beta-Status verlassen und ist nun allgemein verfügbar. Mit WebSockets können Sie eine Zwei-Wege-Kommunikation über eine einzige dauerhafte TCP-Verbindung aufbauen. Mit WebSockets müssen Sie nicht mehrere HTTP-Anfragen und -Antworten verarbeiten. Eine einzige WebSocket-Verbindung ermöglicht die kontinuierliche Kommunikation von Text- und Binärdaten, wobei nur eine einzige Verbindung geöffnet ist.
Während WebSockets den HTTP-Antwort- und -Anfragezyklus vereinfachen können, ist es ein anderes Paradigma, mit dem eine Anwendung erstellt wird. Glücklicherweise verfügen die meisten gängigen Programmiersprachen über WebSocket-Tools, die helfen können, die Komplexität des Prozesses zu verringern.
In diesem Tutorial werden wir einen kleinen Webserver bauen, der mit WebSockets in Ruby arbeitet. Der Server wird eingehende Voice-Anrufe und WebSocket-Verbindungen verarbeiten und HTML darstellen. Wir werden Folgendes verwenden Rack als Webinterface und Thin als unseren Webserver. Für dieses Tutorial sind keine Vorkenntnisse über die Arbeit mit WebSockets erforderlich, aber es setzt leichte Erfahrung in der Arbeit mit Webservern in Ruby voraus.
tl;dr Wenn Sie es überspringen und die Anwendung einfach ausführen möchten, finden Sie eine voll funktionsfähige Version auf GitHub.
Voraussetzungen
Für dieses Tutorial muss Ruby v2.7 oder höher auf Ihrem Rechner installiert sein. Außerdem werden in der Anwendung mehrere Gems verwendet. Jeder von ihnen ist in der Datei Gemfile aufgelistet, die wir später erstellen werden, und wird durch Ausführen von bundle install auf der Kommandozeile installiert:
Wir können nun mit der Implementierung unserer Anwendung beginnen.
Vonage API-Konto
Vonage API-Konto
Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.
In diesem Lernprogramm wird auch eine virtuelle Telefonnummer verwendet. Um eine zu erwerben, gehen Sie zu Numbers > Buy Numbers und suchen Sie nach einer Nummer, die Ihren Anforderungen entspricht.
Der letzte Schritt bei der Einrichtung unseres API-Accounts besteht darin, eine Voice API Application zu erstellen. Wir verknüpfen die virtuelle Telefonnummer, die wir bereitgestellt haben, mit dieser Anwendung und legen die Webhook-URLs fest.
Navigieren Sie im Vonage API Dashboard zu Ihre Applikationen und klicken Sie auf Erstellen Sie eine neue Applikation. Daraufhin wird die folgende Seite angezeigt:
Dashboard Create Application
Die wichtigsten Bereiche, auf die Sie sich bei der Erstellung Ihrer Bewerbung konzentrieren sollten, sind lila hervorgehoben:
Name: Sie können Ihrer Anwendung einen beliebigen Namen geben.
Öffentlicher und privater Schlüssel: Dadurch wird ein öffentliches und privates Schlüsselpaar für die Authentifizierung erzeugt. Eine private Schlüsseldatei wird auf Ihren Computer heruntergeladen. Unsere Anwendung verarbeitet nur eingehende Sprachanrufe, daher müssen wir nichts damit machen.
Fähigkeiten: Jede Applikation kann mehrere Funktionen nutzen. Für unsere Zwecke brauchen wir nur folgende Funktionen zu aktivieren Voice.
Sobald Sie die Optionen ausgewählt haben, können Sie die Schaltfläche Neue Anwendung generieren drücken, um den Vorgang abzuschließen.
Nachdem Ihre Anwendung nun erstellt ist, können wir sie mit Ihrer neu eingerichteten Telefonnummer verknüpfen und die Webhook-URLs festlegen.
Navigieren Sie wie zuvor zu Ihre Applications im Dashboard, klicken Sie auf die Ellipsen neben dem Namen Ihrer Anwendung und dann auf die Schaltfläche bearbeiten. Link.
Innerhalb der Fähigkeiten der Seite sehen Sie die folgenden Optionen:
Application Webhook URL settings
Wir müssen die folgenden Felder ausfüllen Ereignis-URL und die Antwort-URL. An die Ereignis-URL sendet Vonage alle Lebenszyklusdaten des Sprachanrufs. An die letztere Adresse sendet Vonage jeden neuen Voice-Anruf, wenn er initiiert wird. Die hier angegebenen URLs müssen von außen erreichbar sein, damit Vonage sie erreichen kann. Mit anderen Worten, die Verwendung von localhost funktioniert nicht. Eine beliebte Entwicklungsoption ist ngrok, und Sie können unserem Lernprogramm zur Arbeit damit folgen.
Stellen Sie sicher, dass sowohl die Ereignis-URL als auch die Antwort-URL mit /webhooks/event und /webhooks/answerenden.
Außerdem müssen wir unsere Vonage-Telefonnummer mit dieser Anwendung verbinden. Navigieren Sie dazu zu Numbers>Ihre Numbers und klicken Sie auf das Stiftsymbol neben Ihrer Nummer. Sie können dann Ihre neue Anwendung aus den Optionen auswählen, um die Telefonnummer mit ihr zu verknüpfen. Sobald Sie auf Speicherndrücken, werden alle eingehenden Anrufe an diese Nummer an Ihre Anwendung weitergeleitet.
Erstellen der Ordnerstruktur
Nachdem unser Vonage API Account und die Einstellungen fertig sind, können wir nun die Ordnerstruktur für unsere Anwendung erstellen. Sie wird am Ende wie folgt aussehen:
.
+-- recordings/
+-- views/
| +-- index.html.erb
+-- app.rb
+-- GemfileDer Stammordner unserer Anwendung wird Folgendes enthalten app.rbder unser Webserver sein wird, der alle eingehenden Sprachanrufe und WebSocket-Verbindungen verarbeiten wird. Außerdem enthält er den Ordner Gemfileenthalten, in dem wir unsere Abhängigkeiten definieren werden. Es wird zwei weitere Ordner geben: recordings/ und views/. Der Ordner recordings/ Ordner wird die Telefonaufzeichnung der Voice API WebSockets-Verbindung gespeichert. Der Ordner views/ wird die eine Ansicht für die Anwendung gespeichert.
Definieren der Abhängigkeiten
Innerhalb der Gemfile fügen Sie die folgenden Edelsteine hinzu, die wir in der Anwendung verwenden werden:
source 'https://rubygems.org'
gem 'wavefile'
gem 'faye-websocket'
gem 'json'
gem 'rack'
gem 'thin'Jeder Edelstein hat eine bestimmte Funktion:
Wavefile: Mit diesem Edelstein werden wir die rohen Audiodaten in eine WAV-Datei umwandeln
Faye: Wir werden dieses Gem verwenden, um die WebSockets-Verbindung zu handhaben
JSON: Dieser Edelstein wird verwendet, um unsere Anrufanweisungen, die wir an die Vonage Voice API zurücksenden, in JSON zu konvertieren
Rack: Wir werden Rack als unser Web-Framework verwenden
Dünn: Dieser Edelstein stellt uns unseren Webserver auf einem Rack
Sie können nun bundle install von der Befehlszeile aus ausführen, um alle diese Edelsteine für Ihre Anwendung verfügbar zu machen.
Aufbau des Servers
Abhängigkeiten und Variablendefinition
Wir sind nun bereit, unseren Webserver zu bauen. Der erste Punkt beim Aufbau des Servers ist das Hinzufügen mehrerer require und include Anweisungen am Anfang, um die Funktionalität der oben erwähnten Edelsteine in unsere Anwendung zu integrieren:
require 'rack'
require 'erb'
require 'faye/websocket'
require 'json'
require "wavefile"
include Rack
include WaveFileAn diesem Punkt werden wir auch eine konstante Variable definieren, die der von außen zugänglichen URL für unsere WebSockets-Verbindungsanfragen entspricht. Wir werden diese URL in den Anweisungen verwenden, die wir an die Vonage Voice API zurücksenden, wenn wir einen neuen Anruf erhalten:
EXTERNAL_WS_URL = 'ws://example.com/cable'Ersetzen Sie die example.com in dem obigen Ausschnitt durch Ihre von außen zugängliche URL.
Helfer-Methoden
Unsere Anwendung wird die Vorteile von zwei Hilfsmethoden nutzen. Wir können sie jetzt erstellen und sie nach der Deklaration der konstanten Variablen hinzufügen.
Die erste Methode, #create_wav_filehilft bei der Umwandlung der über den WebSocket empfangenen binären Audiodaten in eine WAV-Datei. Sie nutzt die Funktionalität des Wavefile-Gems, um die WAV-Datei zu erstellen, und gibt auch den Namen der Datei zurück, der später in der Anwendung verwendet werden soll:
def create_wav_file(data, file_name)
buffer = Buffer.new(data, Format.new(:mono, :pcm_16, 16000))
puts "Audio Buffer Created..."
writer = Writer.new(file_name, Format.new(:mono, :pcm_16, 16000))
puts "New Audio File Created..."
puts "Writing to the Buffer..."
writer.write(buffer)
puts "Closing Buffer Writing..."
writer.close
puts "WAV File Created..."
file_name
endDie obige Methode legt fest, dass das eingehende Audio von einer mono Quelle statt einer stereo Quelle. Der Unterschied besteht darin, dass es eine einzelne Audiospur gibt, die durch ein flaches Array von Binärdaten definiert ist, und nicht durch ein Array von Arrays von Daten. Der Ton ist definiert als pcm_16definiert, was bedeutet, dass die Quelle Linear PCM 16-bit ist. Schließlich ist die Quelle definiert als 16000definiert, was bedeutet, dass es sich um eine 16KHz-Abtastrate handelt. Die neue WAV-Datei wird mit denselben Audioeinstellungen wie die binären Audiodaten erstellt.
Die zweite Methode, #erbist eine kurze Methode, die wir verwenden werden, um ERB-Vorlagendateien für den Benutzer darzustellen:
def erb(template)
path = File.expand_path("#{template}")
ERB.new(File.read(path)).result(binding)
endDer Rest unseres Codes besteht aus einer Reihe von map Anweisungen, die URL-Routen mit bestimmten Aktionen verbinden, die in Rack::Handler Middleware.
Festlegen der Routen
Die Routen für unsere Anwendung müssen innerhalb der Rack-Middleware definiert werden, die Rack mit Thin verbindet. Wir werden auch die Rack::Static Middleware verwenden, um die statische Audiodatei in der Ansicht bereitzustellen. Hier werden wir auch den Faye WebSocket-Handler initialisieren:
Rack::Handler::Thin.run(Rack::Builder.new {
Faye::WebSocket.load_adapter('thin')
use(Rack::Static, urls: ["/recording"], root: 'recording')Es gibt vier Routen, die wir erstellen müssen map Anweisungen für: /cable, /, /webhooks/answer, und /webhooks/answer. Lassen Sie uns das jetzt tun.
Die erste Route wird die WebSockets-Verbindung verarbeiten:
map('/cable') do
run(->env{
if Faye::WebSocket.websocket?(env)
puts "WebSockets connection opened..."
@call_data = []
ws = Faye::WebSocket.new(env)
ws.on :message do |event|
if event.data.is_a?(Array)
@call_data.append(event.data.pack('c*').unpack('s*'))
else
puts event.data
end
end
ws.on :close do |event|
puts 'WebSocket connection closed...'
create_wav_file(@call_data.flatten, 'recording/recording.wav')
end
ws.rack_response
end
})
end
In der obigen Route wird geprüft, ob die Verbindungsanfrage eine WebSocket-Anfrage ist. Wenn ja, dann instanziieren wir eine neue Instanz von Faye::WebSocket. Es gibt zwei Arten von Daten, die an einen WebSocket gesendet werden können, entweder Text oder binäre Daten. Letztere werden immer in Form von bytegroßen Ganzzahlen in einem Array gesendet.
So können wir prüfen, ob das event.data entweder ein Array-Objekt ist oder nicht. Wenn es ein Array ist, wissen wir, dass es sich um die binären Audiodaten handelt, die wir für unsere WAV-Datei verwenden werden. Ist dies nicht der Fall, handelt es sich um Status-Updates von der Vonage Voice API. In diesem Fall können wir sie auf der Konsole protokollieren.
Ein wichtiger Hinweis, der zu beachten ist: Das Faye WebSockets-Gem konvertiert die binären Daten in Byte-große Integer-Zahlen, wie wir oben erwähnt haben. Dies bedeutet jedoch, dass sie in genau 1 Byte oder 8 Bit große Ganzzahlen umgewandelt werden. Die Vonage Voice API sendet die binären Audiodaten in 16-Bit-Ganzzahlen, einem gängigen Standard für menschliche Sprache. Das bedeutet, dass unsere Anwendung die 8-Bit-Binärdaten in 16 Bit umwandeln muss. Wir verwenden die Methoden der Ruby-Standardbibliothek von #pack und #unpack da wir sie an unsere @call_data Instanzvariable anhängen. Dies ist ein notwendiger Schritt, um verständliches Audio zu erzeugen.
Die nächste Route bedient die index Ansicht. Sie prüft, ob eine Datei vorhanden ist, und wenn ja, übergibt sie mit Instanzvariablen an die Ansicht:
map('/') do
if File.exist?('recording.wav')
@call_status = 'Audio Loaded!'
@file = 'recording.wav'
end
run(->env{
[200, { 'Content-Type' => 'text/html'}, [erb("views/index.html.erb")]]})
end
Die /webhooks/answer Route kehrt zur Vonage Voice API zurück, die spezielle Anweisungen enthält, die ein NCCO (Nexmo Anrufsteuerungsobjekt) die der API mitteilen, was sie mit dem soeben empfangenen Anruf tun soll. Die Anweisung, die wir als JSON zurücksenden, teilt der Voice API mit, dass wir eine WebSocket-Verbindung öffnen wollen und gibt die WebSocket-URL an, um die Verbindung zu starten. Außerdem teilen wir der Voice API mit, dass sie dem Anrufer eine kurze Nachricht zukommen lassen soll, in der sie ihm mitteilt, dass sein Anruf in Kürze gestreamt wird:
map('/webhooks/answer') do
run(->env{
ncco = [
{
"action": "talk",
"text": "You will be streaming momentarily."
},
{
"action": "connect",
"endpoint": [
{
"type": "websocket",
"uri": "#{EXTERNAL_WS_URL}",
"content-type": "audio/l16;rate=16000",
}
]
}
].to_json
[200, { 'Content-Type' => 'application/json' }, [ncco]]
})
end
Die letzte Route, die wir erstellen werden, wird die Ereignislebenszyklusdaten des Anrufs behandeln, die die Voice API an unsere Anwendung sendet. Wir wollen damit nichts weiter tun, als der API zu bestätigen, dass wir sie mit einem 200 Statuscode:
map('/webhooks/event') do
run(->env{
[200, { 'Content-Type' => 'text/html'}, ['']]
})
end
Zum Schluss schließen wir den Rack::Builder Block, den wir ganz am Anfang geöffnet haben, indem wir einen Port angegeben haben, auf dem unsere Anwendung laufen soll:
}, Port: 9292)Das letzte Element, das wir erstellen müssen, bevor wir unsere Anwendung ausführen können, ist unsere Ansicht.
Erstellen der Ansicht
Die Anwendung hat nur eine einzige Ansicht. Auf diese Ansicht kann man zugreifen, indem man die Stamm-URL der Anwendung aufruft, d. h. localhost:9292 oder 127.0.0.1:9292. Die Ansicht präsentiert das abzuspielende Audio mit einem <audio> HTML-Element:
<html>
<head>
<title>Ruby Vonage WebSockets Demo</title>
</head>
<body>
<h1>Vonage WebSockets + Ruby == ♥</h1>
<p>Welcome to the Vonage WebSockets demo in Ruby</p>
<h2>Your Audio To Playback</h2>
<p>Once you have finished your call, your audio will be available to playback from here.</p>
<div id="audio-status">
<%= @call_status %>
<br />
<% if @file %>
<audio
controls
src="recording/<%= @file %>">
Your browser does not support the
<code>audio</code> element.
</audio>
<% end %>
</div>
</body>
</html>
Die Ansicht verwendet die Instanzvariablen, die wir in der Route erstellt haben, um festzustellen, ob das <audio> Element zeigt.
Wir sind nun bereit, die Anwendung zu starten!
Ausführen der Anwendung
Die Anwendung ist nun bereit, ausgeführt zu werden. Um sie auszuführen, führen Sie Folgendes von der Befehlszeile im Stammordner der Anwendung aus:
Vergewissern Sie sich auch, dass Ihr Webserver mit ngrok oder einem ähnlichen Tool von außen zugänglich ist.
Rufen Sie nun Ihre Anwendung an, indem Sie Ihre virtuelle Vonage-Telefonnummer anrufen. Wenn Sie mit dem Sprechen fertig sind, können Sie den Anruf auflegen. Wenn Sie Ihre Anwendung mit Ihrem Webbrowser besuchen, sehen Sie jetzt einen Audioplayer und können Ihre aufgezeichneten Audiodaten abspielen. Herzlichen Glückwunsch!
Weitere Lektüre
In diesem Tutorial wurden die grundlegenden Funktionen für die Nutzung der Vonage Voice API WebSockets in Ruby vorgestellt. Es gibt noch viel mehr, was man mit dieser Funktion machen kann. Wenn Sie mehr über Vonage Voice API WebSockets erfahren möchten, lesen Sie die folgenden Seiten:
Teilen Sie:
Ben ist ein Entwickler im zweiten Beruf, der zuvor ein Jahrzehnt in den Bereichen Erwachsenenbildung, Community-Organisation und Non-Profit-Management tätig war. Er arbeitete als Anwalt für Entwickler bei Vonage. Er schreibt regelmäßig über die Überschneidung von Gemeindeentwicklung und Technologie. Ursprünglich aus Südkalifornien stammend und lange Zeit in New York City ansässig, wohnt Ben jetzt in der Nähe von Tel Aviv, Israel.
