Дмитрий Кайдаш
06.08.2020
78319

Софтфон с технологией WebRTC

В статье мы рассмотрим пример сборки собственного софтфона использующего технологию WebRTC на базе JS библиотеки jssip. Все инструкции тестировались на следующем оборудовании: CentOS Linux release 7.5.1804 Asterisk 13.22.0 Apache/2.4.6 Используемые сторонние библиотеки: Bootstrap 4.5.0 JQuery 3.5.1 JSSIP 3.5.1 SweetAlert 2.1.2 Easytimer FontAwesome 5.13.0 Сразу стоит сказать, что WebRTC работает совместно с другими протоколами и по […]

Софтфон с технологией WebRTC

В статье мы рассмотрим пример сборки собственного софтфона использующего технологию WebRTC на базе JS библиотеки jssip.

Все инструкции тестировались на следующем оборудовании:

  1. CentOS Linux release 7.5.1804
  2. Asterisk 13.22.0
  3. Apache/2.4.6

Используемые сторонние библиотеки:

  • Bootstrap 4.5.0
  • JQuery 3.5.1
  • JSSIP 3.5.1
  • SweetAlert 2.1.2
  • Easytimer
  • FontAwesome 5.13.0
Внимание! Для работы протокола требуется наличие и установка SSL-сертификата.

Сразу стоит сказать, что WebRTC работает совместно с другими протоколами и по сути является надстройкой. Как следствие невозможны соединения вида peer-to-peer. Из положения помогают выходить промежуточные шлюзы, например FreeSwitch или, как в нашем случае, Asterisk.

Допустим, вы являетесь счастливым обладателем программной АТС на базе дистрибутива FreePBX. Для работы с WebRTC проведём следующие подготовительные работы.

  1. Настроим дополнительный web-сервер, который будет принимать соединения на порт 8089

Для этого открываем интерфейс администрирования FreePBX и переходим на вкладку Settings->Advanced settings. Здесь отмечаем всё как показано ниже:

Отображение скрытых настроек

После этого ниже отобразятся новые настройки. Заполняем поля, как на примере:

Настройки web-сервера

Отвлечёмся и добавим на АТС наш SSL-сертификат. Сделать это можно перейдя по ссылке:

Управление сертификатами

Здесь выбираем загрузку сертификата:

Добавление сертификата

В появившейся форме даём своё название сертификату и описание. После чего в назначенные поля вносим содержимое сертификата и его приватного ключа.

Настройки сертификата

Сохраняем и применяем изменения. Так же не забываем отметить использование нашего добавленного сертификата в качестве значения по-умолчанию.

Теперь нам нужно вернуться на вкладку с расширенными настройками Settings->Advanced settings и указать абсолютный путь к файлам ключа и сертификата:

Закрепление сертификата за веб-сервером

Разрешим использование TLS на основании того же сертификата. Переходим по ссылке: Settings->Asterisk SIP settings-> TLS/SSL/SRTP Settings и указываем созданный ранее сертификат.

Поддержка TLS

Теперь в качестве эксперимента можно прописать на сервере и удалённой машине, с которой осуществляется доступ для настройки в файлах hosts доменное имя и попытаться по нему обратиться. Для windows это:

dns на удалённой точке

Для Centos и, соответственно, нашего Asterisk:

dns на АТС

После чего пробуем подключиться уже через доменное имя и проверить доверенность сертификата.

Доступ по защищённому протоколу HTTPS и доменному имени

Последние действия, которые нам предстоит провести на АТС это несколько скорректировать настройки внутреннего номера, а именно:

  1. Отмечаем все пункты, как показано ниже
Доп. настройки номера

2. Добавляем в транспортные протоколы поддержку WSS

Поддержка wss

3. И обозначаем реквизиты для DTLS

Указываем ранее подгруженный сертификат
Внимание! Эти настройки не будут конфликтовать с прочими устройствами и номера можно будет по прежнему регистрировать на софтфоны и стационарные телефоны.

На этом настройки со стороны сервера закончены и можно переходить к инструкциям по самому софтфону. Останавливаться на простых вещах вроде вёрстки и дизайна не будем, заметим лишь что достаточно будет двух форм:

Превая должна содержать типичные поля для регистрации пира на внутренний номер asterisk.

Настройки регистрации

Вторая непосредственно служащая рабочим интерфейсом:

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

Теперь же заглянем под капот. Скрыто от глаз наличие на этой форме трёх элементов тэга <audio>.

  1. Служит для проигрывания сигналов, такие как гудки, рингтон звонка и пр.
  2. Проигрывает голосовой поток вашего собеседника
  3. Используется при поддержке видеосвязи, поэтому опустим пояснения (muted)

Разберём основные фрагменты js-скрипта, который осуществляет взаимодействие с библиотекой jssip.

Объявляем глобальные переменные для хранения ссылок на объекты сессии и устройства:

let phone;
let session;

Таким же образом сразу получаем ссылки на элементы воспроизведения.

let localDevice = $("#localVoice");
let localDetail = localDevice[0];

let remoteDevice = $("#remoteVoice");
let remoteDetail = remoteDevice[0];

let soundDevice = $("#songs");
let soundDetail = soundDevice[0];

Зададим основные параметры звонка и ответа:

let callOptions = {
	pcConfig: {
		hackStripTcp: true,
		iceServers: []
	},
	mediaConstraints: {
		audio: true, 
		video: false
	},
	rtcOfferConstraints: {
		offerToReceiveAudio: true,
		offerToReceiveVideo: false
	}
}

Здесь мы сообщаем об индивидуальной поддержке аудио и запрете передачи видео. Пояснения к параметрам можно найти на сайте разработчика библиотеки по этому адресу.

Так же одними из важных настроек являются параметры передачи DTMF.

let DTMFOptions = {
	duration: 100,
	interToneGap: 500,
	transportType: "RFC2833"
}

Далее нам нужно добавить функцию получения и присвоения голосового потока в элементы аудио.

function streamReroute() {
	session.connection.addEventListener("addstream", function(e) {
		let localStream = session.connection.getLocalStreams();
		if (localStream.length) localDetail.srcObject = localStream[0];

		if (e.stream) remoteDetail.srcObject = (e.stream);
	});
}

И последнее из дополнительных «самописных» элементов: функции проигрывания сигналов и их остановки:

function playSong(src="", loop=false) {
	soundDevice.prop("loop", loop);
	soundDevice.attr("src", src);
	setTimeout(function() {
		soundDevice.trigger("play");
	}, 100);
}

function stopSong(){
	soundDevice.trigger("pause");
}

Теперь функции взаимодействия с самой библиотекой. Получаем из html-формы посредством jquery значения регистрационных данных и сохраняем в переменные.

let host = $("#host").val();
let port = $("#port").val();
let user = $("#user").val();
let secret = $("#secret").val();

let peer = "sip:" + user + "@" + host;

Создаём из полученных данных экземпляр сокета, а его и ряд настроек в свою очередь используем для создания экземпляра устройства.

let socket = new JsSIP.WebSocketInterface("wss://" + host + ":" + port + "/ws");

let regOptions = {
	"sockets"			: [ socket ],
	"uri"      			: peer,
	"contact_uri"		: peer,
	"password"			: secret,
	"register_expires"	: 180
};

// JsSIP.debug.enable("JsSIP:*");
phone = new JsSIP.UA(regOptions);
phone.start();
Внимание! Закомментированная строка позволяет выводить все события в лог консоли режима разработчика браузера. Это очень полезно на стадии разработки, интеграции и тестирования.

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

Успешная регистрация и наличие SSL

Следующее, что стоит упомянуть, это обработчики событий регистрации. Вот они:

phone.on("registered", () => {
	#code here
});

phone.on("registrationFailed", (e) => {
	alert(e.cause);
});

phone.on("unregistered", () => {
	#code here
});

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

Помимо регистрации нам ещё нужно ознакомиться с событиями сессии и их обработчиками:

phone.on("newRTCSession", (e) => {
	let newSession = e.session;
	if (session) session.terminate();
	session = newSession;

	session.on('peerconnection', function() {
		// Если звонок входящий, распределяем потоки
		if (session.direction === 'incoming') streamReroute();
	});

	session.on("progress", () => {
		// Если идёт дозвон, проигрываем гудки
		playSong("sounds/ringing.mp3", true);
		$("#status").html("Ringing...");
	});

	session.on("confirmed", () => {
		// Если звонок принят, останавливаем гудки
		stopSong();
	});

	session.on("ended", (e) => {
		// Если звонок завершён, проигрываем сигнал отбоя и очищаем сессию
		session = null;
		playSong("sounds/busy.mp3", false);
	});

	session.on("failed", (e) => {
		// Аналогично при сбросе звонка
		session = null;
		playSong("sounds/busy.mp3", false);
	});

	if(session.direction === "incoming"){
		// здесь нужно разместить код оповещения о входящем вызове
	}
});

Покажем, как инициировать вызов. Для этого вызывается код:

number = $("#number").val();
if (number != "") {
	session = phone.call(number, callOptions);
	streamReroute();
}

Для отбоя нужно предварительно проверить наличие активной сессии после чего инициировать сброс:

if (session && (session.isEstablished() || session.isInProgress())) session.terminate();

И последнее о чём стоит упомянуть, это отмена регистрации. Для её выполнения достаточно вызвать следующий метод:

phone.stop();

Заключение: таким образом собрав всё в общий листинг, скомпоновав и украсив на свой вкус мы получаем софтфон который может работать в любом браузере и на любом устройстве. Не в последнюю очередь можно заметить, что данное приложение можно встроить в CRM-систему или статистику.

И теперь вы можете скачать и посмотреть небольшой демонстрационный фрагмент:

Подписаться
Уведомить о
guest
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии

Остались вопросы?

Я - Першин Артём, менеджер компании Voxlink. Хотите уточнить детали или готовы оставить заявку? Укажите номер телефона, я перезвоню в течение 3-х секунд.

VoIP оборудование


ближайшие курсы

10 доводов в пользу Asterisk

Распространяется бесплатно.

Asterisk – программное обеспечение с открытым исходным кодом, распространяется по лицензии GPL. Следовательно, установив один раз Asterisk вам не придется дополнительно платить за новых абонентов, подключение новых транков, расширение функционала и прочие лицензии. Это приближает стоимость владения станцией к нулю.

Безопасен в использовании.

Любое программное обеспечение может стать объектом интереса злоумышленников, в том числе телефонная станция. Однако, сам Asterisk, а также операционная система, на которой он работает, дают множество инструментов защиты от любых атак. При грамотной настройке безопасности у злоумышленников нет никаких шансов попасть на станцию.

Надежен в эксплуатации.

Время работы серверов некоторых наших клиентов исчисляется годами. Это значит, что Asterisk работает несколько лет, ему не требуются никакие перезагрузки или принудительные отключения. А еще это говорит о том, что в районе отличная ситуация с электроэнергией, но это уже не заслуга Asterisk.

Гибкий в настройке.

Зачастую возможности Asterisk ограничивает только фантазия пользователя. Ни один конструктор шаблонов не сравнится с Asterisk по гибкости настройки. Это позволяет решать с помощью Asterisk любые бизнес задачи, даже те, в которых выбор в его пользу не кажется изначально очевидным.

Имеет огромный функционал.

Во многом именно Asterisk показал какой должна быть современная телефонная станция. За многие годы развития функциональность Asterisk расширилась, а все основные возможности по-прежнему доступны бесплатно сразу после установки.

Интегрируется с любыми системами.

То, что Asterisk не умеет сам, он позволяет реализовать за счет интеграции. Это могут быть интеграции с коммерческими телефонными станциями, CRM, ERP системами, биллингом, сервисами колл-трекинга, колл-бэка и модулями статистики и аналитики.

Позволяет телефонизировать офис за считанные часы.

В нашей практике были проекты, реализованные за один рабочий день. Это значит, что утром к нам обращался клиент, а уже через несколько часов он пользовался новой IP-АТС. Безусловно, такая скорость редкость, ведь АТС – инструмент зарабатывания денег для многих компаний и спешка во внедрении не уместна. Но в случае острой необходимости Asterisk готов к быстрому старту.

Отличная масштабируемость.

Очень утомительно постоянно возвращаться к одному и тому же вопросу. Такое часто бывает в случае некачественного исполнения работ или выбора заведомо неподходящего бизнес-решения. С Asterisk точно не будет такой проблемы! Телефонная станция, построенная на Asterisk может быть масштабируема до немыслимых размеров. Главное – правильно подобрать оборудование.

Повышает управляемость бизнеса.

Asterisk дает не просто набор полезных функций, он повышает управляемость организации, качества и комфортности управления, а также увеличивает прозрачность бизнеса для руководства. Достичь этого можно, например, за счет автоматизации отчетов, подключения бота в Telegram, санкционированного доступа к станции из любой точки мира.

Снижает расходы на связь.

Связь между внутренними абонентами IP-АТС бесплатна всегда, независимо от их географического расположения. Также к Asterisk можно подключить любых операторов телефонии, в том числе GSM сим-карты и настроить маршрутизацию вызовов по наиболее выгодному тарифу. Всё это позволяет экономить с первых минут пользования станцией.