
Freunde, heute möchte ich mit Ihnen über Anrufe sprechen. Für einige ist dies ein völlig neues Thema. Für andere ist es purer Fan-Spaß auf der Ebene "Aber soll ich mir mein Skype schicken?" Zum dritten ein plötzliches Lebensbedürfnis. Die letzte Option ist unsere Option.
In diesem Artikel zeige ich Ihnen ein kleines, aber sehr praktikables Implementierungsbeispiel, mit dem Sie buchstäblich Ihren eigenen WEB-Dialer erstellen und einen Freund direkt aus dem Browser buchstäblich auf dem Knie mehrerer zehn Javascript-Zeilen anrufen können.
Über Technologien und Protokolle

Es ist 2019, und zu unserer Freude gibt es bereits ein vorgefertigtes Tool für die Implementierung von Real Time Communication (RTC) für das Web, nämlich WebRTC . Vor einigen Jahren war er in der aktiven Entwicklung. Die API wird noch finalisiert, aber die Technologie ist zum De-facto-Standard geworden und wird in den meisten gängigen Browsern unterstützt. In diesem Artikel werden wir uns nicht mit der Technologie selbst befassen. Sie können mehr auf der Entwickler-Website lesen oder nach Artikeln im Hub suchen Zum Beispiel hier .
Aber bevor wir beginnen, möchte ich einige Punkte klarstellen.
- Erstens läuft WebRTC auf einem Bündel von Protokollen, und selbst für die P2P-Kommunikation benötigen Sie eine Art Server, über den Ihre Kunden Freunde finden und sich mit ihnen anfreunden können. In unserem Beispiel wird das SIP-Protokoll verwendet, über das Sie beispielsweise hier mehr lesen können.
- Sie benötigen einen Server mit Unterstützung für alle oben genannten Dinge - wie FreeSwitch oder Asterisk.
Wir lassen diese Dinge außerhalb des Geltungsbereichs des Artikels. Wir gehen davon aus, dass Sie genauso viel Glück haben wie wir und dass Sie bereits VoIP-Telefonie konfiguriert haben.
Nun, der längste Teil des Artikels ist dahinter, lasst uns codieren!
Seitenlayout

Zuerst benötigen wir eine Seite, mit der wir anrufen, Felder zur Eingabe eines Benutzernamens, eines Passworts, einer Telefonnummer und einige Schaltflächen. In der einfachsten Version sieht es ungefähr so aus:
<div class="container"> <div class="input-group mb-6"> <div class="input-group-prepend"> <span class="input-group-text">Login</span> </div> <input id="loginText" type="text" class="form-control"> <div class="input-group-prepend"> <span class="input-group-text">Password</span> </div> <input id="passwordText" type="password" class="form-control"> <button id="loginButton" type="button" class="btn btn-primary" onclick="login()">Login</button> <button id="logOutButton" type="button" class="btn btn-primary d-none" onclick="logout()">LogOut</button> </div> <div class="input-group mb-6 d-none" id="callPanel"> <input id="callNumberText" type="text" class="form-control" placeholder="Call number"> <button id="callNumberButton" type="button" class="btn btn-success" onclick="call()">Call</button> <button id="hangUpButton" type="button" class="btn btn-danger d-none" onclick="hangUp()">Hang Up</button> </div> <audio id="localAudio" autoPlay muted></audio> <audio id="remoteAudio" autoPlay></audio> <audio id="sounds" autoPlay></audio> </div>
Audioelemente „senden“ und „empfangen“ Sound und spielen für die Schönheit durch Sounds DFÜ-Sounds ab.
Die Benutzeroberfläche ist bereit. Sie können UX nicht bemängeln. Lassen Sie es funktionieren.
Wir befestigen JSSIP

Wir werden eine Bibliothek verwenden, in der alles, was benötigt wird, bereits implementiert ist - JSSIP . Sie können sich die Dokumentation ansehen: Dort wird alles ausreichend detailliert beschrieben und es gibt sogar ein fertiges Implementierungsbeispiel. Das heißt, wir müssen praktisch nichts tun - vereinfachen Sie einfach alles so weit wie möglich und finden Sie heraus, was was ist.
Nach Eingabe des Logins / Passworts (muss auf Ihrem Telefonieserver registriert sein) müssen Sie sich beim Server anmelden. Wir machen das:
socket = new JsSIP.WebSocketInterface("wss://webrtcserver:port/ws"); _ua = new JsSIP.UA( { uri: "sip:" + this.loginText.val() + "@webrtcserver", password: this.passwordText.val(), display_name: this.loginText.val(), sockets: [socket] });
Unterwegs können Sie die verbindenden und verbundenen Ereignisse abonnieren und dort etwas Nützliches tun. Aber gehen wir weiter zum Registrierungsereignis:
his._ua.on('registered', () => { console.log("UA registered"); this.loginButton.addClass('d-none'); this.logOutButton.removeClass('d-none'); this.loginText.prop('disabled', true); this.passwordText.prop('disabled', true); $("#callPanel").removeClass('d-none'); });
Hier müssen wir nur den Status der Schaltflächen ändern: Zeigen Sie das Notwendige an, verstecken Sie das Unnötige. Und wenn beim Anmelden plötzlich etwas schief gelaufen ist, haben wir den Fehler im Protokoll ausgespuckt:
this._ua.on('registrationFailed', (data) => { console.error("UA registrationFailed", data.cause); });
Dies reicht für die Anmeldung. Es bleibt die Fassorgel mit zu bekommen
this._ua.start ();
Wenn der Server korrekt angegeben ist und Ihr Benutzername / Passwort akzeptiert wird, werden ein Feld zur Eingabe des Telefons und die Schaltfläche Anrufen angezeigt.
Für die Protokollierung müssen Sie this._ua.stop () aufrufen, alles ist einfach.
Rufen Sie an
Jetzt - das Wichtigste: Sie müssen die eingegebene Nummer anrufen.
this.session = this._ua.call(number, { pcConfig: { hackStripTcp: true,
Bitte beachten Sie: Wir aktivieren explizit das Multiplexen. Diese Einstellung muss auch auf Ihrem Server aktiviert sein. Im Fall eines Sternchens ist dies in den Einstellungen von sip.conf rtcp_mux = yes.
Die weitere Interaktion basiert auf Rückrufen, bei denen wir die Richtung des Audio-Video-Streams zum entsprechenden Seitenelement sicherstellen und die erforderlichen Nachrichten in der richtigen Reihenfolge an den Server senden müssen.
Im Allgemeinen ist alles ziemlich logisch. Während des Wählens ['Fortschritt'] - spielen Sie die Wählgeräusche ab. In unserem Beispiel spielen wir unseren eigenen Sound, aber wie pvsur zu Recht bemerkte, können Sie ihn auch von der angerufenen Seite abrufen und die Antwort des Autoinformers wie "Hinterlassen Sie eine Nachricht nach dem Piepton" hören, falls es einen gibt.
Sobald ich durch ['akzeptiert'] gekommen bin - spielen Sie den Ton beantwortet. Sobald der Teilnehmer den Hörer abhebt, erhalten wir seinen Sound-Stream und legen ihn in das Element remoteAudio ['verbinden' und 'addstream'].
Führen Sie am Ende des Anrufs closeMediaStream aus. Sie können sich entspannen.
Ein bisschen über die Bedienung
Beim Testen wurden zwei Dinge entdeckt.
- In Chrom gab es zu Beginn des Wählens eine Verzögerung von mehreren Sekunden, was sehr ärgerlich war. Wir haben aus den Protokollen herausgefunden, dass er zum Eisserver gegangen ist, was überhaupt nicht erforderlich war, da wir unseren eigenen Server haben. Daher haben wir sie in der Konfiguration für JSSIP einfach entfernt und sind sofort hübscher geworden. Siehe pcConfig.iceServers und pcConfig.hackStripTcp.
- Unser Stern hat ein WSS-Protokoll mit Verschlüsselung für SIP. Dies wird vom Browser bei Verwendung der HTTPS-Website benötigt. Das Sternchen verwendet jedoch WS basierend auf den Kontaktparametern, in denen die JSSIP-Bibliothek einen fest codierten WS-Deskriptor enthält. Die Entwickler der Bibliothek verweisen gleichzeitig auf Standards, in denen zu diesem Thema wirklich keine Anforderungen bestehen. Und Kollegen von der Aster wollen beharrlich nichts reparieren. Im Allgemeinen eine Sackgasse. Nun, zu diesem Zeitpunkt finden wir in der Quelle die Zeile this._configuration.contact_uri = new URI (...), ändern Sie transport: 'ws' in transport: 'wss' und genießen Sie weiterhin das Leben.
Im Allgemeinen ist das Beispiel fertig, Sie können es annehmen und anrufen. Sie müssen keine Softphones verwenden oder eigene entwickeln. Sie müssen sich keine Gedanken über die Bereitstellung dieser Software für Kundenautos machen. Öffnen Sie einfach den Browser und rufen Sie an.
In einer anderen Bibliothek können Sie im Tonmodus zusätzliche Nummern wählen. Das heißt, Sie können beispielsweise das Callcenter der Bank anrufen und zum gewünschten Element im Sprachmenü gelangen. Führen Sie dazu einfach den folgenden Befehl aus:
this._call.sendDTMF('. ')
Über Fakapy

Es gab mehrere Punkte, die mich wirklich nervös machten.
Ich habe diesen Teil außerhalb des Geltungsbereichs des Artikels belassen, aber zusätzlich zu ausgehenden Anrufen mussten wir auch eingehende Anrufe annehmen. Und für einige Zeit musste ich mich mit einem eingehenden Anruf hocken, der kam und dann abbrach. Alles wurde durch die oben erwähnte Einstellung rtcpMuxPolicy entschieden, die das Multiplexen auf dem Sternchen ermöglichte, aber wir waren einige Zeit dumm.
Und es gibt immer noch Probleme, sich selbst zu wählen - wenn ein Anruf und ein Anruf auf demselben Computer getätigt werden. Ich erinnere mich nicht genau, aber die Verbindung wurde erfolgreich hergestellt, es gab keine Fehler und auch keinen Ton :) Die Zeit lief ab, also haben wir diesen Spezialeffekt erzielt. Beachten Sie jedoch, dass das Testen eingehender Anrufe in einem separaten Auto besser ist.
Fazit
Abschließend möchte ich darauf hinweisen, dass wir das JSSIP + Asterisk-Bundle in unserem Callcenter getestet haben. Alles funktioniert einwandfrei, zumindest in Chrom, was uns vollkommen zusagt. Die Hauptsache ist, dem Browser den Zugriff auf Mediengeräte zu ermöglichen und Benutzer auf dem Dialer-Server zu registrieren.
Sie können das fertige Beispiel auf dem Github sehen .
Nützliche Links
Über webrct
Über SIP: tyts , tyts
Über Asterisk
Jssip-Bibliothek