javascript

Несколько строк JS кода для звонка из браузера на мобильный телефон

  • суббота, 29 апреля 2017 г. в 03:14:47
https://habrahabr.ru/company/flashphoner/blog/327466/
  • Разработка систем связи
  • Разработка веб-сайтов
  • Программирование
  • JavaScript
  • Блог компании Flashphoner


Flashphoner.createSession(...).createCall({callee:'+74957718000'}).call();

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

Схема звонка


Прежде всего, потребуется SIP-аккаунт оператора VoIP телефонии. Оператор «приземляет» звонок, идущий по интернету (VoIP) и дозванивается до мобильного или городского телефона.

Наши задачи в этом случае следующие:

  1. Послать SIP INVITE в сторону SIP оператора.
  2. Принять SIP 200 OK от оператора.
  3. Принять звук от оператора.
  4. Отправить звук из браузера оператору.

Браузер не работает по честным SIP / TCP и SIP / UDP протоколам, поэтому в нашей схеме будет сервер-посредник, который будет говорить с оператором на классическом SIP / UDP.


SIP аккаунт


Чтобы получить SIP аккаунт, можно зарегистрироваться, например в сервисе VoIP телефонии sipnet или у любого другого провайдера, который предоставляет линии для звонков на мобильные телефоны.

SIP аккаунт состоит из шести следующих параметров:

  1. Логин
    Например alice123
  2. Имя для аутентификации (может отличаться от логина или совпадать).
    Например alice123
  3. Пароль
    Например ******
  4. Домен
    Например sipnet.ru
  5. Прокси (может отличаться от домена или совпадать)
    Например sipnet.ru
  6. Порт (обычно 5060)
    Например 5060

Упрощенный SIP аккаунт


Часто бывает, что domain совпадает с outbound proxy и login совпадает с authentication name, и порт используется стандартный 5060. В этом случае SIP оператор может предоставить SIP аккаунт в упрощенном виде:
Login alice123
Password ***
Domain sipnet.ru

Это уже чем-то похоже на привычный доступ к веб ресурсу. После того, как доступ получен можно протестировать его с любым из софтфонов, например Xlite, Linphone, Ekiga, и т.д.

Тест с десктопным софтфоном


При использовании софтфона Bria 4, настройки подключения по SIP выглядят так:


Обычно провайдер предоставляет номера, на которые можно сделать SIP-звонок. Некоторые провайдеры дают бесплатные минуты при минимальном пополнении счета.

Осталось позвонить с софтфона и убедиться в том, что SIP звонки действительно проходят на нормальные телефоны. Например, позвоним в Минкомсвязь по телефону +74957718000.


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

HTML страница для звонка


Браузерные звонки будут идти по технологии WebRTC через сервер Web Call Server 5, который с одной стороны работает с браузером по WebRTC, а с другой созванивается с SIP оператором по SIP.


Код HTML-страницы, с которой выполняются звонки довольно компактный и занимает 14 строк:

<!DOCTYPE html>
<html>
<head lang="en">
   <script type="text/javascript" src="flashphoner.js"></script>
    <script language="javascript" src="click-to-call.js"></script>
</head>
<body onload="init_page()">
<button id="callButton" type="button" onclick="connectAndCall('+74957718000')">Call</button>
<button id="hangupButton" type="button" onclick="hangup()">Hangup</button>
<div id="remoteMedia" style="visibility: hidden"></div>
<div id="localMedia" style="visibility: hidden"></div>
<p id="status"></p>
</body>
</html>

На странице размещена кнопка Call для звонка и кнопка Hangup для его сброса. Есть поле, в котором отображается статус.

Div — элементы localMedia и remoteMedia используются для внедрения в страницу объектов, отвечающих за получение и отправку звука.

Скрипт flashphoner.js доступен для скачивания в сборке Web SDK.

Скрипт click-to-call.js для звонка


Скрипт click-to-call.js содержит 97 строк. С помощью этого скрипта устанавливается коннект к серверу и делается звонок.

var localMedia;
var remoteMedia;
var outCall;

//init API
function init_page() {
    Flashphoner.init();
    localMedia = document.getElementById("localMedia");
    remoteMedia = document.getElementById("remoteMedia");
}

//call
function connectAndCall(number) {

    //if already connected, make a call
    if (Flashphoner.getSessions().length > 0) {
        call(number, Flashphoner.getSessions()[0]);
    } else {

        //SIP credentials
        var sipOptions = {
            login: "10001",
            authenticationName: "10001",
            password: "12345",
            domain: "192.168.1.3",
            outboundProxy: "192.168.1.3",
            port: "5060",
            registerRequired: false
        };

        var connectionOptions = {
            urlServer: "wss://wcs5-eu.flashphoner.com:8443",
            sipOptions: sipOptions
        };

        //create new connection to WCS server
        Flashphoner.createSession(connectionOptions).on(Flashphoner.constants.SESSION_STATUS.ESTABLISHED, function (session) {
            setStatus("Session", Flashphoner.constants.SESSION_STATUS.ESTABLISHED);
            //session connected, place call
            call(number, session);
        }).on(Flashphoner.constants.SESSION_STATUS.DISCONNECTED, function () {
            setStatus("Session", Flashphoner.constants.SESSION_STATUS.DISCONNECTED);
            onHangup();
        }).on(Flashphoner.constants.SESSION_STATUS.FAILED, function () {
            setStatus("Session", Flashphoner.constants.SESSION_STATUS.FAILED);
            onHangup();
        });
    }
}

function call(number, session) {

    //disable call button
    document.getElementById("callButton").disabled=true;

    var constraints = {
        audio: true,
        video: false
    };

    //prepare outgoing call
    outCall = session.createCall({
        callee: number,
        visibleName: "Click To Call",
        localVideoDisplay: localMedia,
        remoteVideoDisplay: remoteMedia,
        constraints: constraints,
        receiveAudio: true,
        receiveVideo: false
    }).on(Flashphoner.constants.CALL_STATUS.RING, function () {
        setStatus("Call", Flashphoner.constants.CALL_STATUS.RING);
    }).on(Flashphoner.constants.CALL_STATUS.ESTABLISHED, function () {
        setStatus("Call", Flashphoner.constants.CALL_STATUS.ESTABLISHED);
    }).on(Flashphoner.constants.CALL_STATUS.FINISH, function () {
        setStatus("Call", Flashphoner.constants.CALL_STATUS.FINISH);
        onHangup();
    }).on(Flashphoner.constants.CALL_STATUS.FAILED, function () {
        setStatus("Call", Flashphoner.constants.CALL_STATUS.FAILED);
        onHangup();
    });

    outCall.call();
}

function hangup() {
    if (outCall) {
        outCall.hangup();
    }
}

function onHangup(){
    //will be invoked on hangup
}

function setStatus(callOrSession,status){
    document.getElementById("status").innerHTML= callOrSession +" "+status;
}

В данном скрипте можно отметить четыре основных функции:

  • Инициализация
  • Установка соединения с сервером
  • Звонок
  • Сброс звонка

Инициализация


Здесь мы просто вызываем функцию init() и тем самым инициализируем API.

Flashphoner.init();

Установка соединения с сервером


Здесь мы подключаемся к серверу по защищенному протоколу websockets и передаем данные SIP аккаунта, для того, чтобы сервер, в свою очередь смог подключиться к SIP оператору (провайдеру).

 var sipOptions = {
            login: "10001",
            authenticationName: "10001",
            password: "12345",
            domain: "192.168.1.3",
            outboundProxy: "192.168.1.3",
            port: "5060",
            registerRequired: false
};

var connectionOptions = {
            urlServer: "wss://wcs5-eu.flashphoner.com:8443",
            sipOptions: sipOptions
};

Flashphoner.createSession(connectionOptions);

Звонок


Создаем звонок и вызываем метод call() для вызова. При создании звонка передается параметр callee — это номер абонента, которому звоним, например номер мобильного.

outCall = session.createCall({
        callee: number,
        visibleName: "Click To Call",
        localVideoDisplay: localMedia,
        remoteVideoDisplay: remoteMedia,
        constraints: constraints,
        receiveAudio: true,
        receiveVideo: false
});

outCall.call();

Сброс звонка


Для того, чтобы сбросить звонок, вызываем метод API hangup()

outCall.hangup();

Тестируем страницу звонка


Для тестирования в Google Chrome нужно залить страницы click-to-call.html и click-to-call.js на web-сервер с поддержкой https. Chrome дает доступ к микрофону только с защищенных страниц (https). Код скриптов доступен для скачивания по этой ссылке.

Скрипты соединяются с тестовым сервером wss://wcs5-eu.flashphoner.com:8443. Для тестирования с собственным сервером, вам нужно установить сервер WCS5 на Linux систему. Скачать сервер WCS5 можно по этой ссылке.

Открываем страницу click-to-call.html в браузере Google Chrome и нажимаем кнопку Call. Сервер принимает вызов и присылает статус ESTABLISHED. Мобильный абонент берет трубку и в результате устанавливается звонок между браузером и мобильным телефоном.


Таким образом, мы разобрали, как выглядят SIP-аккаунты, предоставляемые провайдерами IP-телефонии, протестировали звонки с софтфонами, создали два файла для звонка из браузера click-to-call.html и click-to-call.js и протестировали эти скрипты звонком из браузера Google Chrome на мобильный телефон, через SIP-оператора. Звонок из браузера идет на Web Call Server 5 и далее на SIP оператора с приземлением на мобильный телефон.

Ссылки


SIP — протокол установки сессии, который используется в VoIP телефонии
Web Call Server — WebRTC-SIP шлюз для работы браузеров с SIP телефонией.
Web SDK — JavaScript API сервера для разработки браузерных телефонов. Сборка содержит скрипт flashphoner.js.
Source — скрипты click-to-call.html и click-to-call.js