Использование webrtc для взаимодействия с asterisk-сервером или как заставить рации говорить с браузером

в 12:21, , рубрики: asterisk, javascript, RTLS, SIPML5, WebRTC, Беспроводные технологии, Блог компании RTL-Service, голосовая связь, локальное позиционирование, Разработка систем связи

Доброго времени суток, читатели.
Сегодня я расскажу вам о работе sip-телефонии, а именно о том, как я организовывал звуковой сеанс между мобильными рациями (или ИКН) о которых вы слышали ранее из других статей нашей компании и web-клиентом через webRTC с использованием sipML5 в качестве библиотеки и asterisk 11 в качестве АТС.
image
Всем кому небезразлична данная тема — добро пожаловать под кат.

Немного предыстории

К нам в отдел поступило оперативное задание разработать sip-клиент, который работал бы на asterisk, и как минимум на google chrome (как мобильной, так и десктопной его версии). С этого и закрутилось.

В системе локального позиционирования RealTrac существуют мобильные устройства типа рация, или, как мы их называем, ИКН (интерком носимый), который обеспечивает использование как дуплексной связи, так и широковещательной полудуплексной связи с другими устройствами. Эти устройства взаимодействуют с коммуникационным сервером INCPd, основная задача которого – обработка пакетов протокола INCP, посредством которого обеспечивается обмен информацией с устройствами системы RealTrac. В том числе, данный сервер обрабатывает поступающий голосовой трафик, и перепаковывает его в sip-пакеты, для дальнейшей работы со сторонним софтом.
В качестве коммутатора выступает asterisk.

image

Инструментарий

SipML5 был выбран нами неслучайно. Во-первых, данная библиотека хорошо подходит для интеграции с asterisk. Во-вторых, мы уже имели опыт работы с подобными системами, однако, из-за того, что наша компания поддерживала Debian 7 в качестве ОС для нашего программного обеспечения имелись определенные сложности. В дистрибутиве Debian 7 доступен только asterisk 1.8 в то время как webRTC без танцев с бубном, в виде webrtc2sip, работает только с 11 версии asterisk, что нас несильно устраивало, так как это могло бы стать полигоном проблем для будущих инсталляций.
С релизом Debian 8 было решено продолжить движение в направлении данного функционала.
В качестве инструментария создания ui-части выступал React.js, так как он удобен для отображения различных динамических объектов, имеющих большое количество внутренних состояний.

Небольшое введение по sipML5

В основе клиента используется две основные сущности, это SIPml.Stack и SIPml.Session.

SIPml.Stack является управляющим потоком данных. Данный объект будет выступать в качестве основного при создании сессий с сервером.

SIPml.Session является потоком sip-сеанса с сервером. Используется непосредственно для передачи данных между сервером и клиентской частью.

Алгоритм работы с sipML5:

Инициализация библиотеки:

SIPml.init(readyCallback, errorCallback);

Создание Stack

Stack является ключевым источником данных для работы клиента.

RtlsSip.stack = new SIPml.Stack({
   realm: Data.property.realm,
   impi: Data.property.impi,
   impu: Data.property.impu,
   password: Data.property.password,
   display_name: Data.property.display_name,
   websocket_proxy_url: Data.property.websocket_proxy_url,
   events_listener: { events: '*', listener: eventsListener },
   sip_headers: [
       { name: 'User-Agent', value: 'IM-client/OMA1.0 sipML5-v1.0.0.0' },
       { name: 'Organization', value: 'RTLS' }
   ]
})

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

После создания stack-объекта необходимо его запустить:

RtlsSip.stack.start();

Важно отметить, что функция start() является асинхронной, поэтому, перед тем как начать совершать звонки, необходимо дождаться события запуска stack.
Полный перечень событий представлен тут много, и перечислять их все не имеет смысла.

После события создания stack необходимо создать сессию регистрации:

RtlsSip.stack.newSession('register', {
   events_listener: { events: '*', listener: registerListeners} });
RtlsSip.sessions.register();

В ходе этой операции происходит sip запрос для входа пользователя в систему.

После выполнения данных действий мы готовы совершать или принимать звонки от пользователей.

Прием звонков

Входящий звонок в sipML5 инициализирует событие ”i_new_call” объекта SIPml.Stack.
В общем случае обработчик ответа на звонок выглядит следующим образом:

var eventCallback = function(е){
RtlsSip.callSession =  e.newSession;
RtlsSip.callSession.events_listener({events: '*', listener:      RtlsSip.sessionEventListener})
RtlsSip.callSession.accept(
{audio_remote: document.getElementById('audio_remote'),
   	 events_listener: { events: '*', listener:  RtlsSip.sessionEventListener}})

}

e.newSession — содержит в себе дополнительный объект сеанса связи, для события “i_new_call” это будет объект SIPml.Session.Call.

Функция accept() необходима для принятия звонка. В качестве параметра принимает объект SIPml.Session.Configuration

Инициализация звонков

Инициализация звонка сводится к созданию новой сессии типа SIPml.Session.Call

RtlsSip.callSession = RtlsSip.stack.newSession('call-audio', {
   audio_remote: document.querySelector('#audio_remote'),
   events_listener: { events: '*', listener: RtlsSip.sessionEventListener }
});

После инициализации можно приступать к вызову абонента, через его идентификатор, номер или url (e.g. 'sip:johndoe@example.com' or 'johndoe' or '+33600000000').:

RtlsSip.callSession.call(number);

Управление звонком
Управление звонком это методы класса SIPml.Session.Call

Основные из них:
● .hangup() — завершение звонка
● .hold() / .resume() — удержание/возобновление звонка
● .mute(media, mute) — отключение входящего звука, где media — тип контента для отключения; mute — boolean — активация/деактивация mute.
RtlsSip.callSession.mute('audio', true);

Есть также множество других функций, информацию о которых вы найдете здесь.

Схема приложения:

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

image

Интеграция в систему

Настройки для asterisk сервера я здесь описывать не буду, так как их несложно найти на просторах сети.
Для абонентов типа web-client был выделен собственный список номеров. Номера из пула устанавливаются диспетчерам при создании аккаунта пользователя.
Диспетчер может совершать звонки как в полудуплексном, так и в дуплексном режиме, а также связываться с другими диспетчерами в случае необходимости.
Устройство по умолчанию звонит в полудуплексном режиме. Диспетчер, которому звонит устройство выбирается в зависимости от геосегмента в котором находится устройство в текущий момент времени.
Все это позволяет добиться максимального комфорта в использовании системы.
Итоги:
На данный момент, эта технология проходит у нас процесс интеграции и тестирования. Уверен, что в процессе работы найдется немало помех и проблем.
Вполне возможно, что в будущем мы попробуем решение на основании других технологий, предоставляющих тот же функционал.

by Sinires

Автор: RTL-Service

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js