Web Sip клиент на основе JsSIP + FreePBX

от автора

У FreePBX есть Web Sip клиент. Мне было интересно как он работает. Начав изучать технологию WebRTC я наткнулся на 3 библиотеки — это JsSIP, его fork SIP.js, а также sipml5.

JsSIP и SIP.js не удалось запустить с первого раза, не хватало опыта. А вот sipml5 оказался самым простым в применении. Скачав его тестовую версию, получилось совершить первый звонок.

Все 3 библиотеки работоспособны. У каждой есть свои сильные и слабые стороны. Протестировав все 3 библиотеки, остановил выбор на JsSIP.

Основные плюсы и минусы с которыми я столкнулся:

1. JsSIP

Плюсы:

  • легковесная;
  • активно поддерживается разработчиками.

Минусы:

  • на начальном этапе более сложная для старта;
  • пришлось править исходники чтобы заработал с asterisk.

2. Sip.js

Плюсы:

  • легковесная;
  • упор делается для работы с asterisk.

Минусы:

  • не удалось запустить звук для Early media (не подключается звук для предответных сообщении оператора).

3. Sipml5

Плюсы:

  • относительно простая для новичков.

Минусы:

  • сложный и запутанный код, не было желания разбираться в нем.

Подготовка

Веб клиент работает только на странице с поддержкой шифрования. Нам нужно создать самоподписанный сертификат. Как это делается есть готовые статьи в Интернете.

Firefox разрешает работать с самоподписанными сертификатами. Для работы в Хроме придется делать сначала корневой сертификат, а на его основе уже подписывать сертификат для работы телефона. Корневой сертификат должен быть импортирован в хранилище сертификатов.

Включение поддержки web sip клиента на FreePBX

Администратор -> User Managment -> Вкладка «Groups» -> Вкладка «UCP» -> Вкладка «Phone»
Для свойства «Enable Phone» выбираем значение «Да».

Если у вас в FreePBX были внутренние номера, допустим 200, то при активации web sip клиента появятся дополнительные номера с префиксом 99, т.е. 99200.

На клиентском браузере, после того как дали разрешение на использование самоподписанного сертификата, нужно еще дать разрешение для сертификата asterisk. Для этого наберите в браузере

https://192.168.1.70:8089/ws

IP-адрес нужно указать тот, на котором запущен asterisk.

Правка исходника JsSIP

В исходниках библиотеки JsSIP необходимо заменить transport=ws на transport=wss. Без этой правки клиент не заработает. В Sip.js править ничего не нужно, там этот момент предусмотрели.

Код web sip клиента на основе JsSIP

Для демонстрации работы клиента скопируйте нижеприведенный код, сохраните и запустите страницу. Страница демонстрирует исходящий звонок. Код 100% рабочий, проверил прежде чем выложить.

 <!DOCTYPE HTML> <html> <head> <script type="text/javascript" src="/lib/jquery-3.4.1.js"></script> <script type="text/javascript" src="/lib/jsSIP/jssip.min.js"></script> </head> <body> <style> #callControl {     display:flex;     flex-direction:column;     justify-content:flex-start;     align-items: center; } #num {     margin-top: 20px;     padding-left: 10px;     font-size: 1em;     font-family:'Open Sans', sans-serif;     width: 300px;     height: 40px;     border:0px;     border-bottom: 1px solid #B8B8B8; } #call {     display:flex;     background-color: #389400; } #hangup {     display:none;     background-color:#A90002; } #call, #hangup {     flex-direction:column;     justify-content:center;     align-items: center;     color: #FFF;     width:260px;     height: 40px;     font-size: 20px;     margin: 20px;     border-radius: 20px;     cursor: pointer; } </style> <div id="callControl">   <h2>Web Sip клиент на основе JsSIP</h2>   <div id="to">     <input id="num" type="text" placeholder="Введите номер телефона"/>   </div>   <div id="call">Вызов</div>   <div id="hangup">Завершить</div> </div>  </body> <script> JsSIP.debug.enable('JsSIP:*'); var socket = new JsSIP.WebSocketInterface('wss://192.168.1.70:8089/ws'); var configuration = { 	sockets  : [ socket ], 	// внутренний номер	 	uri      : '99XXX@192.168.1.70', 	// пароль 	password : 'passw' };  var remoteAudio = new window.Audio(); remoteAudio.autoplay = true;  var ua = new JsSIP.UA(configuration);  // События регистрации клиента ua.on('connected', function(e) { /* Ваш код */ }); ua.on('disconnected', function(e) { /* Ваш код */ });  ua.on('registered', function(e) { /* Ваш код */ }); ua.on('unregistered', function(e) { /* Ваш код */ }); ua.on('registrationFailed', function(e) { /* Ваш код */ });  // Запускаем  ua.start();  // Обработка событии исх. звонка var eventHandlers = { 	'progress': function(e) { 		console.log('call is in progress');  		session.connection.ontrack = function(e) { 			console.log(e); 			remoteAudio.srcObject = e.streams[0]; 		}; 	}, 	'failed': function(e) { 		console.log('call failed with cause: ' + e.cause); 		$('#call').css({'display' : 'flex'}); 		$('#hangup').css({'display' : 'none'}); 	}, 	'ended': function(e) { 		console.log('call ended with cause: ' + e.cause); 		$('#call').css({'display' : 'flex'}); 		$('#hangup').css({'display' : 'none'}); 	}, 	'confirmed': function(e) { 		console.log('call confirmed'); 		console.log(e); 	} };  var options = { 	'eventHandlers'    : eventHandlers, 	'mediaConstraints' : { 'audio': true, 'video': false } };  // Кнопка для звонка $('#call').click(function(e) { 	session = ua.call($('#num').val(), options); 	$('#call').css({'display' : 'none'}); 	$('#hangup').css({'display' : 'flex'}); });  // Кнопка для отбоя звонка $('#hangup').click(function() { 	if (session) { 		session.terminate(); 	}  	$('#call').css({'display' : 'flex'}); 	$('#hangup').css({'display' : 'none'}); }); </script> </html> 

Должна получиться такая страница:

Теперь можно пробовать совершить первый звонок. Если все сделали правильно, то услышите гудок, при ответе должен пойти звук в обе стороны. Начинаем полноценную беседу.

Итоги

За последние 2 года использования Web sip клиента были проблемы, которые появлялись при обновлении браузера.

Например в 63 версии Firefox пришлось менять SDP протокол, чтобы сессия не отбивалась. Браузер перестал держать связь без параметра a=mid:0. В последних версиях уже не актуально, ошибку исправили, в более поздних версиях уже нет такой проблемы.

В 65 версии Firefox при исх. звонке начал пропадать голос собеседника, в локалке не было таких проблем. Проблема только при вызове наружу через шлюз. В хроме такой проблемы не наблюдалось, все работает стабильно.

В основном пользователи работают в Firefox, и по этой причине пришлось в библиотеке убрать повторное согласование SDP протокола. Проблемы с пропаданием звука после ответа перестали беспокоить.

Перспективы

В данный момент на js была написана программа «Автообзвон», которая способна по первым нескольким секундам распознавать предответные сообщения оператора такие как: тел. не существует, абон. занят, тел. отключен, тел. доступен. Точность распознавания 95% и выше. Если будет время, напишу статью и опишу алгоритм.

ссылка на оригинал статьи https://habr.com/ru/post/507554/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *