Недавно был разработан стандарт WebRTC, позволяющий организовать потоковую передачу данных между браузерами. Chrome 17, Opera 12, Firefox 18 (а также версии, выше указанных) в той или иной мере уже поддерживают этот стандарт. Так же существует расширение webrtc4all, которое позволяет остальным браузерам работать с WebRTC. Я не буду здесь описывать преимущества, недостатки и перспективы технологии, перейду сразу к практическому использованию.
Также существует сервис Plivo, позволяющий управлять звонками в реальном времени с помощью API. Для осуществления звонков клиент может создать SIP аккаунт или арендовать номер. На данный момент доступны номера в сорока с лишним странах, среди которых России, к сожалению, нет. Также через API можно создавать, изменять и удалять номера и аккаунты. Еще одна важная вещь, которую имеет plivo, — это приложения (applications). Приложения позволяют объединять номера и SIP аккаунты. В настройках приложения есть обязательная опция — Answer URL, и две необязательных — Fallback URL и Hungup URL. Собственно с этих URL'ов Plivo и получает команды для управления звонками.
Подробно об API можно прочитать здесь. Опишу только те части, которые использованы при создании телефона. Для управления звонками вам нужно при запросе на Answer URL возвращать XML с командами. Таким образом можно перенаправить звонок на какой-либо номер, отклонить звонок, проиграть музыку, прочитать текст. Plivo всегда отправляет на Answer URL данные о входящем и исходящем звонке. API для управления номерами, аккаунтами и приложениями — простые HTTP запросы к определенным URL'ам с определенными параметрами. Plivo предоставляет библиотеки для упрощения работы с API https://github.com/plivo. Я использовал plivo-php. Не забудьте установить зависимости для этой библиотеки — php-curl, php-openssl, pear package HTTP_Request2. Также был использован Javascript API непосредственно для клиентской части телефона. Это API позволяет залогиниться с помощью SIP аккаунта, сделать, принять, отклонить звонок непосредственно в браузере.
Мне нужно было создать телефон для сайта, где регистрируются компании в качестве групп, участники которых — сотрудники компаний. Каждый сотрудник или отдел имеет свой номер, поэтому необходимо было связать номер и SIP аккаунт. Можно, обойтись без арендованных номеров, но тогда звонить с обычного телефона в браузер будет проблематично.
Вкратце объясню, как все это будет работать. Каждый пользователь на сайте имеет свой SIP аккаунт и арендованный номер. Все SIP аккаунты должны быть привязаны к одному приложению (назовем его DirectDial Application), все номера должны быть привязаны к другому приложению (назовем его Number Application). Разные номера могут быть привязаны к разным приложениям, как это было сделано у меня, так как на сайте существуют разные группы пользователей. Однако Answer URL у них может быть и одинаковым. Когда пользователь загружает страницу, с помощью js API мы будем логиниться, используя соответствующий SIP аккаунт. Далее пользователь может совершать звонки из браузера. Данные о таких звонках будут отправлены на Answer URL DirectDial Application'a. Answer URL всегда должен возвращать какой-либо XML ответ, так как Plivo не будет звонить на набранный пользователем номер, если не отправить соответствующую команду. Данные о входящем звонке отправляются на Answer URL Number Application'a. Здесь та же ситуация — ответ должен быть отправлен в любом случае. В моем случае я просто искал в базе SIP аккаунт, соответствующий набраному номеру и перенаправлял звонок на этот аккаунт, далее в браузере пользователь видел входящий звонок.
Для начала нужно создать DirectDial Application. Идем по адресу https://www.plivo.com/app/create/ и создаем приложение. В Application name пишем DirectDial Application (можно любое другое название), в Answer URL соответствующий URL (пусть будет site.com/dda_answer). Отметьте чекбокс Default endpoint application, далее жмем Create. Endpoint это то же самое, что SIP аккаунт. Я не специалист в SIP протоколе, и не могу сказать какое название более корректно. При исходящем звонке с SIP аккаунта на site.com/dda_answer будет приходить POST запрос с примерно такими параметрами:
[Direction] => inbound
[From] => sip:sipname8905@phone.plivo.com
[CallerName] => sipname8905
[BillRate] => 0.00400
[To] => called_number
[CallUUID] => 138caf72-615d-11e2-8f6e-659f0688e76c
[CallStatus] => ringing
[Event] => StartApp
Практически всегда Direction будет inbound. Поэтому тип звонка лучше определять исходя из параметров From и To. Самый простой ответ на этот запрос:
<?xml version="1.0" encoding="utf-8"?>
<Response>
<Dial callerId="rented_number">
<Number>called_number</Number>
</Dial>
</Response>
В резуьтате будет вызван номер called_number, у которого в качестве входящего номера высветиться rented_number. В моем случае это был арендованный номер, соответствующий аккаунту sipname8905. XML можно создать с помощью plivo-php. Called_number должен быть передан в виде 795023423434, то есть без знака «+» перед номером и должен содержать код страны, города и сотового оператора.
Когда звонок будет закончен, также будет отправлен запрос на Answer URL (если вы указали Hangup URL при создании приложения, то запрос будет отправлен на него). Параметры запроса выглядят примерно так:
[Direction] => inbound
[BillDuration] => 0
[From] => sip:sipname8905@phone.plivo.com
[CallerName] => sipname8905
[HangupCause] => USER_BUSY
[BillRate] => 0.00400
[To] => called_number
[Duration] => 0
[CallUUID] => 138caf72-615d-11e2-8f6e-659f0688e76c
[CallStatus] => busy
[Event] => Hangup
CallStatus и HangupCause могут быть другими. Это случай, когда номер был занят.
Здесь пример скрипта для Answer URL DirectDial Application'a. Я использовал этот пример, добавив к нему методы для сохранения истории исходящих вызовов. Самый простой ответ выглядит так:
<?xml version="1.0" encoding="utf-8"?>
<Response>
<Hangup/>
</Response>
Теперь перейдем к Number Application. Также нужно создать новое приложение, указав другой Answer URL, отмечать чекбокс Default endpoint application не нужно. Если у вас это единственное приложение для арендованных номеров, то можно отметить Default number application. Теперь, когда кто-то будет звонить на арендованный номер, который привязан к Number Application'у, Plivo отправит запрос на Answer URL этого приложения. Параметры запроса будут выглядеть примерно так:
[Direction] => inbound
[From] => calling_number
[CallerName] => +calling_number
[BillRate] => 0.00900
[To] => rented_number
[CallUUID] => 4f26b9b5-4468-4d95-8f52-e24b084b8a76
[CallStatus] => ringing
[Event] => StartApp
Ответ на этот запрос также должен быть обязательно отправлен. В моем случае я ищу в базе SIP аккаунт, соответствующий rented_number, и перенаправляю звонок на SIP аккаунт. Ответ выглядет так:
<?xml version="1.0" encoding="utf-8"?>
<Response>
<Dial callerId="calling_number">
<User>related_endpoint</User>
</Dial>
</Response>
Связь между SIP аккаунтом и номером хранится у меня в базе, поэтому не стоит пытаться искать как это сделать через API или в настройках на Plivo. Скрипт очень похож на тот, что использован для Answer URL DirectDial Application'a. В этом месте как раз можно создать автоответчик, отправляя ответы с необходимыми командами. Также, если при создании Number Application вы не указали Hangup URL, то при завершении звонка придет такой же запрос, как и для Answer URL DirectDial Application'a. И ответ здесь может быть таким же.
Теперь перейдем к самому интересному — к телефону. Пример можно посмотреть здесь. Для начала подключаем js, предоставленный Plivo
<script type="text/javascript" src="https://s3.amazonaws.com/plivoweb-sdk/plivo.min.js"></script>
Теперь мы можем инициализировать объект Plivo
Plivo.onWebrtcNotSupported = webrtcNotSupportedAlert;
Plivo.onReady = onReady;
Plivo.init();
webrtcNotSupportedAlert — пользовательская функция, которая будет вызвана после инициализации в случае, если браузер не поддерживает технологию webRTC. оnReady будет вызвана в случае если браузер поддерживает webRTC. В методе onReady как раз удобно залогинить пользователя, если логин и пароль определены заранее, и привязать методы к событиям Plivo. Приведу пример минимально необходимого кода.
onIncomingCall = function (acc_name) {
//сообщить пользователю о входящем звонке
$('#answer-button').click(function(){Plivo.conn.answer();});
}
onReady = function () {
Plivo.conn.login(username, pass);
Plivo.onIncommingCall = onIncommingCall;
$('#button-call').click(function(){
var numb = $('#number-textfield').val().replace(/[D,s]/g, '');
Plivo.conn.call(numb);
});
$('#button-hangup').click(function(){
Plivo.conn.hangup();
});
}
Список всех событий доступен здесь. Также можно установить свой рингтон и что-то свое вместо гудков.
Данный сервис удобно использовать для создания горячей линии, или для того, чтобы дать возможность клиентам из другой страны легко и дешево связаться с вами, арендовав номер в этой стране.
Но не обойдется и без ложки дегтя. Работает это пока что только в Chrome. Причем наблюдаются проблемы со звуком в версиях 24 и 25. В Chrome 23 все прекрасно работало.
Автор: serega_kaktus