
Teman, hari ini saya ingin berbicara dengan Anda tentang panggilan. Bagi sebagian orang, ini adalah topik yang sama sekali baru. Bagi yang lain, ini benar-benar kegembiraan penggemar di tingkat "tetapi haruskah saya mengirim Skype saya kepada saya?" Untuk yang ketiga, kebutuhan mendadak untuk hidup. Opsi terakhir adalah opsi kami.
Pada artikel ini saya akan menunjukkan kepada Anda contoh implementasi yang kecil namun sangat layak yang akan memungkinkan Anda untuk benar-benar membuat dialer WEB Anda sendiri dan memanggil teman langsung dari browser secara harfiah di atas beberapa puluh garis javascript.
Tentang teknologi dan protokol

Ini tahun 2019, dan yang menggembirakan kami, sudah ada alat yang siap pakai untuk mengimplementasikan komunikasi komunikasi (RTC) untuk web, yaitu WebRTC . Beberapa tahun yang lalu dia dalam pengembangan aktif. API masih diselesaikan, tetapi teknologi ini telah menjadi standar de facto dan didukung di sebagian besar browser populer. Pada artikel ini, kami tidak akan membahas teknologi itu sendiri, Anda dapat membaca lebih lanjut di situs web pengembang atau mencari artikel di hub Misalnya di sini .
Tetapi sebelum kita mulai, saya ingin mengklarifikasi beberapa poin.
- Pertama, WebRTC berjalan di atas sekumpulan protokol, dan bahkan untuk komunikasi P2P Anda akan memerlukan beberapa jenis server yang melaluinya klien Anda dapat menemukan dan berteman satu sama lain. Contoh kami akan menggunakan protokol SIP, yang dapat Anda baca lebih lanjut, katakanlah, di sini .
- Anda akan memerlukan server dengan dukungan untuk semua hal di atas - seperti FreeSwitch atau Asterisk.
Kami meninggalkan hal-hal ini di luar ruang lingkup artikel. Kami akan menganggap bahwa Anda seberuntung kami, dan Anda telah mengkonfigurasi telepon VoIP yang Anda inginkan.
Nah, bagian terpanjang dari artikel ini ada di belakang, mari kode!
Tata letak halaman

Pertama, kita membutuhkan halaman yang akan kita panggil, bidang untuk memasukkan nama pengguna, kata sandi, nomor telepon, dan beberapa tombol. Dalam versi paling sederhana, akan terlihat seperti ini:
<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>
Elemen audio akan โmengirimโ dan โmenerimaโ suara, dan untuk keindahan, melalui suara, memutar suara dial-up.
UI siap, Anda tidak dapat menemukan kesalahan dengan UX, mari kita membuatnya bekerja.
Kami kencangkan JSSIP

Kami akan menggunakan perpustakaan di mana segala sesuatu yang diperlukan sudah diterapkan - JSSIP . Anda dapat melihat dokumentasi: semuanya dijelaskan secara cukup rinci di sana dan bahkan ada contoh implementasi yang sudah jadi. Artinya, kita praktis tidak perlu melakukan apa pun - cukup sederhanakan segala sesuatunya dan cari tahu apa itu.
Setelah memasukkan login / kata sandi (harus terdaftar di server telepon Anda), Anda harus masuk ke server. Kami melakukan ini:
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] });
Sepanjang jalan, Anda dapat berlangganan acara yang terhubung dan terhubung dan melakukan sesuatu yang bermanfaat di sana. Tapi mari kita beralih ke acara pendaftaran:
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'); });
Di sini kita hanya perlu mengubah status tombol: perlihatkan yang diperlukan, sembunyikan yang tidak perlu. Dan jika tiba-tiba ada yang tidak beres dengan login, kami meludahkan kesalahan dalam log:
this._ua.on('registrationFailed', (data) => { console.error("UA registrationFailed", data.cause); });
Ini cukup untuk login. Masih untuk mendapatkan organ barel dengan
this._ua.start ();
Jika server ditentukan dengan benar dan nama pengguna / kata sandi Anda diterima, bidang untuk memasukkan telepon dan tombol Panggil akan muncul.
Untuk login, Anda perlu memanggil this._ua.stop (), semuanya sederhana.
Lakukan panggilan
Sekarang - hal yang paling penting: Anda perlu memanggil nomor yang dimasukkan.
this.session = this._ua.call(number, { pcConfig: { hackStripTcp: true,
Harap dicatat: kami secara eksplisit mengaktifkan multiplexing, pengaturan ini juga harus diaktifkan di server Anda. Dalam kasus tanda bintang, ini adalah rtcp_mux = yes di pengaturan sip.conf.
Interaksi lebih lanjut didasarkan pada panggilan balik, di mana kita harus memastikan arah aliran audio-video ke elemen halaman yang sesuai dan mengirim pesan yang diperlukan dalam urutan yang benar ke server.
Secara umum, semuanya cukup logis. Saat memanggil ['progres]] - mainkan suara panggilan. Dalam contoh kita, kita memainkan suara kita sendiri, tetapi seperti yang dikatakan pvsur dengan benar, Anda juga dapat memperolehnya dari sisi yang dipanggil dan mendengar respons autoinformer seperti "tinggalkan pesan setelah bunyi bip", jika ada.
Segera setelah saya melewati ['diterima'] - mainkan suara yang dijawab. Segera setelah pelanggan mengangkat telepon, kami akan menerima aliran suaranya dan memasukkannya ke elemen remoteAudio ['connecting' dan 'addstream'].
Di akhir panggilan, lakukan closeMediaStream. Kamu bisa santai.
Sedikit tentang operasi
Selama pengujian, dua hal ditemukan.
- Di chrome, ada penundaan beberapa detik di awal panggilan, yang sangat mengganggu. Kami mengetahui dari log bahwa ia pergi ke server es, yang tidak diperlukan sama sekali, karena kami memiliki server kami sendiri. Oleh karena itu, dalam konfigurasi JSSIP, kami cukup menghapusnya, dan segera menjadi lebih cantik. Lihat pcConfig.iceServers dan pcConfig.hackStripTcp.
- Tanda bintang kami memiliki protokol WSS dengan enkripsi untuk SIP. Ini diperlukan oleh browser saat menggunakan situs web HTTPS. Tapi tanda bintang menggunakan WS berdasarkan parameter kontak di mana pustaka JSSIP berisi deskriptor WS hardcoded. Pengembang perpustakaan pada saat yang sama menunjukkan standar di mana sebenarnya tidak ada persyaratan tentang hal ini. Dan kolega dari aster terus-menerus tidak ingin memperbaiki apa pun. Secara umum, jalan buntu. Nah, pada saat ini kita menemukan di baris sumber this._configuration.contact_uri = new URI (...), ubah transport: 'ws' to transport: 'wss' dan terus nikmati hidup.
Secara umum, contoh sudah siap, Anda dapat menerima dan menelepon. Tidak perlu meletakkan softphones atau mengembangkan sendiri. Tidak perlu khawatir tentang penyebaran perangkat lunak ini ke mobil klien. Cukup buka browser dan panggil.
Pustaka lain memungkinkan Anda untuk memanggil nomor tambahan dalam mode nada. Artinya, Anda dapat menelepon, misalnya, pusat panggilan bank dan mendapatkan item yang diinginkan pada menu suara. Untuk melakukan ini, jalankan perintah berikut:
this._call.sendDTMF('. ')
Tentang Fakapy

Ada beberapa poin yang benar-benar membuat saya gugup.
Saya meninggalkan bagian ini di luar ruang lingkup artikel, tetapi selain panggilan keluar, kami juga perlu menerima panggilan masuk. Dan untuk beberapa waktu saya harus jongkok dengan panggilan masuk, yang datang dan kemudian terputus. Semuanya diputuskan oleh pengaturan rtcpMuxPolicy yang disebutkan di atas dan memungkinkan multiplexing pada asterisk, tapi kami bodoh untuk beberapa waktu.
Dan masih ada masalah dengan panggilan sendiri - ketika panggilan dan panggilan dilakukan pada mesin yang sama. Saya tidak ingat persis, tetapi koneksi berhasil dibuat, tidak ada kesalahan dan tidak ada suara juga :) Waktu hampir habis, jadi kami memberi skor pada efek khusus ini. Tetapi perlu diingat bahwa menguji panggilan masuk lebih baik pada mobil yang terpisah.
Kesimpulan
Akhirnya, saya ingin mencatat bahwa kami menguji bundel JSSIP + Asterisk di call center kami, semuanya berfungsi dengan baik, setidaknya dalam chrome, yang sangat cocok untuk kami. Hal utama adalah untuk memungkinkan akses browser ke perangkat media dan mendaftarkan pengguna di server dialer.
Anda dapat melihat contoh yang sudah selesai di github .
Tautan yang bermanfaat
Tentang webrct
Tentang SIP: tyts , tyts
Tentang Asterisk
Perpustakaan jssip