Делаем видео-чат в веб-браузере с минимумом трудозатрат

  • Tutorial
Для реализации функционала видео-чата в браузере существует две наиболее подходящие из технологии — WebRTC и Flash. Каждая из технологий обладает рядом своих особенностей, например, во Flash можно использовать видео кодеки H.264 или Sorenson, а в WebRTC на текущий момент доступен VP8, что делает два этих подхода плохо совместимыми друг с другом (перекодирование видео на лету — это очень затратная операция), к тому же видео-чат лучше делать peer-to-peer по возможности, стоит ли говорить, что соединить Flash и WebRTC напрямую не выйдет. В нашем примере мы рассмотрим вариант видео-звонка звонка из WebRTC в WebRTC, с помощью платформы VoxImplant. В целом, можно сделать выбор конкретного варианта, вплоть до динамического выбора технологии в зависимости от того кому звоним. Подробности, как обычно, под катом.

Создание приложения, пользователей, сценария и настройка

Для начала нам потребуется аккаунт разработчика VoxImplant (регистрация тут), после входа в панель управления VoxImplant в разделе Applications создаем новое приложение и называем его videochat. Чтобы организовать простой видео-чат нам потребуется хотя бы 2 пользователя — testuser1 и testuser2, создаем их в разделе Users и привязываем к приложению, используя кнопку Assign applications (аналогично можно уже созданных юзеров привязать к приложению во время редактирования приложения). При звонке от пользователя к пользователю все равно вызывается сценарий обработки звонка, который пишутся на Javascript и выполняется движком VoxEngine. Создаем в разделе Scenarios новый сценарий, назовем его User2User, при использовании режима peer-to-peer сценарий будет выглядеть следующим образом:
VoxEngine.forwardCallToUserDirect();

Если в будущем захочется гонять видео через сервер (принудительно), то можно использовать
VoxEngine.forwardCallToUser(null, true);
, но в этом случае звонки будут стоить денег.


Если необходимо управлять сигнализацией, чтобы, например, завершить звонок в какой-то момент со стороны сервера, то можно вместо хелпера forwardCallToUserDirect использовать следующий сценарий:

var call1, call2;

VoxEngine.addEventListener(AppEvents.CallAlerting, function(e) {  
  call1 = e.call;
  call2 = VoxEngine.callUserDirect(e.call, e.destination, e.displayName, e.headers);
  call2.addEventListener(CallEvents.Connected, handleCallConnected);
});

function handleCallConnected(e) {
  call1.answerDirect(call2);
  // Тут можно, например, разъединить звонок через какое-то время
  setTimeout(VoxEngine.terminate, 5000);
}


После создания сценария нам нужно привязать его к приложению через правило (Rule) — идем в раздел Applications и редактируем наше приложение, в табе Rules создаем новое правило (Add rule). Назвать можно как угодно, например, Intercom, в Pattern указывается регулярное выражение — правило срабатывает если номер соот-вует этому выражению, оставляем .* и перетаскиваем наш сценарий User2User из Available в Assigned и сохраняем правило. Сохраняем приложение, остается только сделать клиент с помощью VoxImplant Web SDK.

Создание веб-клиента

Для клиента потребуется только файл voximplant.min.js, который лежит на cdn, а также базовое понимание как устроено Web SDK. Чтобы все выглядело все более-менее прилично можно использовать Bootstrap. Не вижу смысла вываливать сюда весь код из HTML-файла, разберем только основные моменты, а более глубоко разобраться всегда можно, скачав файлы с нашей странички на GitHub.

// Подключаем SDK
<script type="text/javascript" src="//cdn.voximplant.com/edge/voximplant.min.js"></script>
//функция для выведения лога сразу в HTML
function log(str) {
  document.getElementById("log").innerHTML += str+"<br/>";
}

// Создаем инстанс VoxImplant 
var voxAPI = VoxImplant.getInstance();
// Вешаем обработчики событий
voxAPI.on(VoxImplant.Events.SDKReady, onSdkReady);
voxAPI.on(VoxImplant.Events.ConnectionEstablished, onConnectionEstablished);
voxAPI.on(VoxImplant.Events.ConnectionFailed, onConnectionFailed);
voxAPI.on(VoxImplant.Events.ConnectionClosed, onConnectionClosed);
voxAPI.on(VoxImplant.Events.AuthResult, onAuthResult);
voxAPI.v(VoxImplant.Events.IncomingCall, onIncomingCall);
voxAPI.on(VoxImplant.Events.MicAccessResult, onMicAccessResult);

// Инициализуем SDK
try {
    voxAPI.init({ 
        micRequired: true, // запрос доступа к микрофону/камере до подключения к VoxImplant
        videoSupport: true // включить поддержку видео
    });
} catch(e) {
    // если произошла ошибка инициализации, то выводим ее
    log(e.message);
}

// Теперь можно пользоваться SDK - подключаемся
function onSdkReady(){        
    voxAPI.connect(); // после вызова появится диалог доступа к камере/микрофону
}

// Обрабатываем
function onMicAccessResult(e) {
    if (e.result) {
        // разрешили доступ к камере/микрофону

    } else {
        // запретили доступ к камере/микрофону
    }
}

// Установили соединение с VoxImplant
function onConnectionEstablished() {
    // Можно авторизоваться - тут надо показать диалог для ввода данных, а потом вызвать следующую функцию
    // Замените application_user, application_name, account_name и application_user_password на ваши данные для тестирования
    voxAPI.login(application_user+"@"+application_name+"."+account_name+".voximplant.com", application_user_password);
}

// Не смогли подключиться к VoxImplant
function onConnectionFailed() {
    // Или веб-сокеты не подключились или UDP закрыто
}

// Закрылось соединение
function onConnectionClosed() {
    // Можно вызвать connect по новой для переподключения
}

function onAuthResult(e) {
    if (e.result) { 
        // авторизовались - теперь можно звонить или принимать звонки
    } else {
        // ошибка авторизации, можно посмотреть e.code, чтобы понять что не так
    }
}

var currentCall = null; // текущий звонок

// Входящий звонок
function onIncomingCall(e) {
    currentCall = e.call;
    // Вешаем обработчики
    currentCall.on(VoxImplant.CallEvents.Connected, onCallConnected);
    currentCall.on(VoxImplant.CallEvents.Disconnected, onCallDisconnected);
    currentCall.on(VoxImplant.CallEvents.Failed, onCallFailed);
    // Отвечаем на звонок автоматически. В нормальном приложении лучше показать инфо о входящем звонке и дать возможность принять или отбить.
    currentCall.answer(null, {}, { receiveVideo: true, sendVideo: true });
}

// Функция для исходящего звонка
function createCall() {
    // application_username - имя юзера, которому звонит (по видео)
    currentCall = voxAPI.call(application_username, { receiveVideo: true, sendVideo: true }, "TEST CUSTOM DATA", {"X-DirectCall": "true"});
    // Вешаем обработчики
    currentCall.on(VoxImplant.CallEvents.Connected, onCallConnected);
    currentCall.on(VoxImplant.CallEvents.Disconnected, onCallDisconnected);
    currentCall.on(VoxImplant.CallEvents.Failed, onCallFailed);
}

// Звонок соединился
function onCallConnected(e) {  
  // Включаем отправку видео и показываем входящее видео        
  voxAPI.sendVideo(true);
  currentCall.showRemoteVideo(true);
}

// Звонок завершился
function onCallDisconnected(e) {
  currentCall = null;
}

// Ошибка при звонке
function onCallFailed(e) {
  // Код ошибки e.code, описание ошибки e.reason
}


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






В случае если нужна поддержка и Flash и WebRTC придется переключать клиентское приложение в соответствующий режим, потому что видео-звонки WebRTC<>Flash мы реализовывать не стали. Надеемся, что в ближайшем будущем поддержка WebRTC появится в IE12, а за ним и в Safari. Если у вам нужен вариант «звонок с сайта оператору», то можно сделать 2 операторских приложения, одно с использованием WebRTC, другое с использованием Flash, и направлять звонки с сайта в зависимости от того какой режим SDK включится у посетителя сайта или на одного или на другого оператора.

Файлы проекта на GitHub

Only registered users can participate in poll. Log in, please.

Планируете ли вы в будущем реализовывать видео-звонки в каком-нибудь из своих проектов?

Voximplant
195.01
Облачная платформа голосовой и видеотелефонии
Share post

Comments 17

    0
    Стянул ради интереса с гитхаба, попробывал, ничего не вышло:
    image
      0
      Нужно index.html#accname=Имя_аукаунта_voximplant, Readme допишем еще
        0
        Жду с нетерпением, заинтересовало, спасибо!
        0
        #accname эффекта не дал, либо делаю что не так :(
          0
          А что пишет в консоли? Должно быть ок
            0
            Вообще, судя по внешнему виду скриншота, дело не в accname :) Браузер на вид Firefox? в нем должно все работать, если версия хотя бы более-менее свежая. Посмотрите, что пишет в консоли, явно какая-то ошибка возникает, еще до запроса девайса
              0
              Вы правы!
              GET https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js [HTTP/1.1 407 Proxy Authentication Required 103мс] GET http://www.air-kub.ru/vox/js/bootstrap-dialog.js [HTTP/1.1 407 Proxy Authentication Required 61мс] GET http://www.air-kub.ru/vox/js/app.js [HTTP/1.1 407 Proxy Authentication Required 79мс] ReferenceError: showLog is not defined index.html:33
              Видать на работе не получится, попробую дома.
              Спасибо!
        0
        Нет кнопки принять звонок. Что я делаю не так? Гудок идёт, вкладка «звонит».
          0
          В приложении включен автоматический ответ на входящий звонок, можете поменять код и сделать такую кнопку
          +1
          а есть ли пример, как можно добиться такого же эффекта без стороннего сервиса?
            0
            Кстати, в последний Firefox Nightly добавили WebRTC, если кому-то интересно.
              0
              WebRTC в Firefox уже 100 лет как есть, в последнем Nightly максимум что могли — добавить поддержку H.264, но это пока мало кому чем поможет.
                0
                я, наверное, слегка не так выразился. Имелось в виду это:
              0
              1. Соединение только Точка-точка.
              Или возможно например устроить конференцию 1 к 5 точкам?

              2. Я правильно понял, что P2P бесплатно, а если через ваше облако то стоит 0,4 cent за минуту
                0
                Можно сделать конференцию, но для каждого участника нужно будет создать свой звонок, использование канала тоже будет неоптимальным — на каждого участника будет создаваться свой исходящий поток. По поводу цен — верно.
                0
                Здравствуйте! По неизвестной пока причине не у меня одного изображение с камеры не транслируется на экран. Сама камера включается.
                В логах получаю:
                onSDKReady version 3.6.363
                WebRTC supported: true
                Mic/Cam access allowed: true
                Mic/Cam access allowed: false
                Connection established: true

                Only users with full accounts can post comments. Log in, please.