
Amis, aujourd'hui, je veux vous parler des appels. Pour certains, c'est un sujet complètement nouveau. Pour d'autres, c'est un pur plaisir pour les fans au niveau "mais dois-je m'envoyer mon Skype?" Pour le troisième, un besoin de vie soudain. La dernière option est notre option.
Dans cet article, je vais vous montrer un exemple d'implémentation petit mais très viable qui vous permettra de créer littéralement votre propre numéroteur WEB et d'appeler un ami directement à partir du navigateur littéralement sur les genoux de plusieurs dizaines de lignes javascript.
À propos des technologies et des protocoles

Il y a 2019 dans la cour et, à notre grande joie, il existe déjà un outil prêt à l'emploi pour la mise en œuvre de la communication réaliste (RTC) pour le Web, à savoir WebRTC . Il y a quelques années, il était en développement actif. L'API est toujours en cours de finalisation, mais la technologie est devenue la norme de facto et est prise en charge dans la plupart des navigateurs. Dans cet article, nous ne nous attarderons pas sur la technologie elle-même, vous pouvez en savoir plus sur le site Web des développeurs ou rechercher des articles sur le hub Par exemple, ici .
Mais avant de commencer, je veux clarifier quelques points.
- Tout d'abord, WebRTC fonctionne au-dessus d'un ensemble de protocoles, et même pour la communication p2p, vous aurez besoin d'une sorte de serveur à travers lequel vos clients peuvent se trouver et se lier d'amitié. Notre exemple utilisera le protocole SIP, dont vous pouvez en savoir plus, disons ici .
- Vous aurez besoin d'un serveur prenant en charge toutes les fonctionnalités ci-dessus - comme FreeSwitch ou Asterisk.
Nous laissons ces choses en dehors du champ d'application de l'article. Nous supposerons que vous avez autant de chance que nous et que vous avez déjà configuré la téléphonie VoIP à votre disposition.
Eh bien, la partie la plus longue de l'article est derrière, codons!
Mise en page

Tout d'abord, nous avons besoin d'une page avec laquelle nous appellerons, de champs pour entrer un nom d'utilisateur, un mot de passe, un numéro de téléphone et quelques boutons. Dans la version la plus simple, cela ressemblera à ceci:
<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>
Les éléments audio «envoient» et «reçoivent» le son, et pour la beauté, à travers les sons, émettent des sons d'accès à distance.
L'interface utilisateur est prête, vous ne pouvez pas trouver de problème avec UX, faisons-le fonctionner.
Nous fixons JSSIP

Nous utiliserons une bibliothèque dans laquelle tout ce qui est requis est déjà implémenté - JSSIP . Vous pouvez voir la documentation: tout est décrit assez en détail et il y a même un exemple d'implémentation prêt à l'emploi. Autrement dit, nous n'avons pratiquement rien à faire - il suffit de tout simplifier autant que possible et de comprendre ce qui est quoi.
Après avoir entré le login / mot de passe (doit être enregistré sur votre serveur de téléphonie), vous devez vous connecter au serveur. Nous faisons ceci:
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] });
En cours de route, vous pouvez vous abonner aux événements connectés et connectés et y faire quelque chose d'utile. Mais passons à l'événement d'inscription:
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'); });
Ici, il suffit de changer l'état des boutons: afficher le nécessaire, masquer l'inutile. Et si soudainement quelque chose a mal tourné avec la connexion, nous crachons l'erreur dans le journal:
this._ua.on('registrationFailed', (data) => { console.error("UA registrationFailed", data.cause); });
Cela suffit pour la connexion. Reste à obtenir l'orgue de Barbarie avec
this._ua.start ();
Si le serveur est spécifié correctement et que votre nom d'utilisateur / mot de passe est accepté, un champ pour entrer le téléphone et le bouton d'appel apparaîtra.
Pour la journalisation, vous devez appeler this._ua.stop (), tout est simple.
Passer un appel
Maintenant - la chose la plus importante: vous devez appeler le numéro entré.
this.session = this._ua.call(number, { pcConfig: { hackStripTcp: true,
Remarque: nous activons explicitement le multiplexage, ce paramètre doit également être activé sur votre serveur. Dans le cas d'un astérisque, il s'agit de rtcp_mux = yes dans les paramètres sip.conf.
L'interaction ultérieure est basée sur des rappels, dans lesquels nous devons assurer la direction du flux audio-vidéo vers l'élément de page correspondant et envoyer les messages nécessaires dans le bon ordre au serveur.
En général, tout est assez logique. Pendant la numérotation [«progression»] - jouez les sons de la numérotation. Dans notre exemple, nous jouons notre propre son, mais comme le fait remarquer à juste titre pvsur , vous pouvez également l'obtenir du côté appelé et entendre la réponse de l'autoinformateur comme «laisser un message après le bip», le cas échéant.
Dès que je suis passé [«accepté»] - jouez le son a répondu. Dès que l'abonné décroche le téléphone, nous récupérons son flux audio et le mettons dans l'élément remoteAudio ['connexion' et 'addstream'].
À la fin de l'appel, fermez MediaStream. Vous pouvez vous détendre.
Un peu sur le fonctionnement
Lors des tests, deux choses ont été découvertes.
- En chrome, il y avait un retard de plusieurs secondes au début de la numérotation, ce qui était très gênant. Nous avons découvert dans les journaux qu'il était allé au serveur de glace, ce qui n'était pas du tout nécessaire, car nous avons notre propre serveur. Par conséquent, dans la configuration de JSSIP, nous les avons simplement supprimés et sommes immédiatement devenus plus jolis. Voir pcConfig.iceServers et pcConfig.hackStripTcp.
- Notre astérisque a un protocole WSS avec cryptage pour SIP. Ceci est requis par le navigateur lors de l'utilisation du site Web HTTPS. Mais l'astérisque utilise WS en fonction des paramètres de contact dans lesquels la bibliothèque JSSIP contient un descripteur WS codé en dur. Les développeurs de la bibliothèque indiquent en même temps des normes dans lesquelles il n'y a vraiment aucune exigence à ce sujet. Et les collègues de l'aster ne veulent toujours rien réparer. En général, une impasse. Eh bien, à ce moment, nous trouvons dans la source la ligne this._configuration.contact_uri = nouvel URI (...), changez le transport: 'ws' en transport: 'wss' et continuez à profiter de la vie.
En général, l'exemple est prêt, vous pouvez prendre et appeler. Pas besoin de mettre de softphones ni de développer le vôtre. Pas besoin de vous soucier du déploiement de ce logiciel sur les voitures clientes. Ouvrez simplement le navigateur et appelez.
Une autre bibliothèque vous permet de composer des numéros supplémentaires en mode tonalité. Autrement dit, vous pouvez bien appeler, par exemple, le centre d'appels de la banque et accéder à l'élément souhaité dans le menu vocal. Pour ce faire, exécutez simplement la commande suivante:
this._call.sendDTMF('. ')
À propos de Fakapy

Il y avait plusieurs points qui me rendaient vraiment nerveux.
J'ai laissé cette partie en dehors du champ d'application de l'article, mais en plus des appels sortants, nous avons également dû accepter les appels entrants. Et pendant un certain temps, j'ai dû m'accroupir avec un appel entrant, qui est venu puis s'est interrompu. Tout a été décidé par le paramètre rtcpMuxPolicy mentionné ci-dessus et permettant le multiplexage sur l'astérisque, mais nous avons été stupides pendant un certain temps.
Et il y a toujours des problèmes avec la numérotation vous-même - lorsqu'un appel et un appel sont effectués sur le même appareil. Je ne me souviens pas exactement, mais la connexion a été établie avec succès, il n'y a pas eu d'erreurs ni de son non plus :) Le temps étant compté, nous avons donc marqué sur cet effet spécial. Mais gardez à l'esprit qu'il est préférable de tester les appels entrants sur une voiture séparée.
Conclusion
Enfin, je tiens à noter que nous avons testé le bundle JSSIP + Asterisk dans notre centre d'appels, tout fonctionne bien, au moins en chrome, ce qui nous convient parfaitement. L'essentiel est de permettre au navigateur d'accéder aux périphériques multimédias et d'enregistrer les utilisateurs sur le serveur de numérotation.
Vous pouvez voir l'exemple fini sur le github .
Liens utiles
À propos de webrct
À propos de SIP: tyts , tyts
À propos d'Asterisk
Bibliothèque Jssip