Тут-тук, відкрийте



Всім знову привіт! На цих вихідних я виступав на DevFest Siberia 2016 з проектом IoT домофона. Це була неймовірно атмосферний конференція. Але розмова не про неї. Під час доповіді я пообіцяв, що окремо розповім на Хабре, як організувати аналог технології Knock Knock з Google DUO в домофоні.

Невелика довідка від Google:
«Коли ви телефонуєте контакту у Duo, абонент може побачити ваше відео, якщо ви входите в число його контактів. Ви побачите абонента тільки після того, як він відповість на виклик».

У цьому туториале ми будемо робити код домофона, так що одна сторона буде вміти дзвонити, друга сторона буде вміти приймати дзвінки. Дивно, якщо б ви дзвонили на домофон, це як дзвінки на таксофон.

Щоб зробити повноцінний відео чат, досить просто об'єднати код обох прикладів на одній сторінці.

Викликає сторона
Давайте зробимо трохи html+css, щоб було красиво. Що вийде в підсумку, ви можете подивитися на КДПВ статті.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>Intercom</title>
<script type="text/javascript" src="//cdn.voximplant.com/edge/voximplant.min.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<!-- У цьому блоці ми спочатку покажемо своє відео, а потім і якщо нам дадуть відповідь, віддалене відео -->
<div class="it_remote_wrapper">
<div class="it_remote_video"></div>
</div>
<!-- У цьому блоці буде наше відео, коли нам дадуть відповідь-->
<div class="it_local_video"></div>
<!-- Скасування дзвінка -->
<div class="it_exit_link">
<i class="material-icons">call_end</i>
</div>
<!-- Напівпрозорий банер в шапці -->
<div class="it_connecting">
З'єднуємо <br> з квартирою
<br>
чекайте
</div>
<!-- Дзвінок гудка -->
<audio src="/assets/31800_81339-lq.mp3" id="beeptone" loop autoplay></audio>
</body>
</html>

Приймаюча сторона
<div class="mdl-layout mdl-js-layout">
<main class="mdl-layout__content">
<h1>Please, wait incoming call.</h1>
</main>
<div class="callpopup">
<div class="it_remote_wrapper">
<div class="it_remote_video"></div>
</div>
<div class="it_local_video"></div>
<div class="it_exit_link">
<i class="material-icons">call_end</i>
</div>
<div class="it_start_link">
<i class="material-icons">call</i>
</div>
<div class="it_connecting">
Incoming call
</div>
</div>

Про верстку особливо нічого сказати. Це справа смаку і переваг.

Тепер додамо сценарій на Voximplant.

VoxEngine.forwardCallToUserDirect(function(call1,call2){
call2.addEventListener. (CallEvents.InfoReceived,function(e){
call1.sendMessage(e.body);
});
},true);

Цей код дозволяє провести дзвінок в режимі P2P і передати між телефонами власну сигналізацію про початок дзвінка. Тут варто розповісти про те, як взагалі буде проходити дзвінок і чим цей сценарій відрізняється від звичайного дзвінка.

Загалом, схема така:

  • Павло А викликає Павла Б
  • Павло Б приймає дзвінок, але не відсилає свої медіа потоки
  • Павло Б бачити Павла А і на вигляд вирішує, чи варто відповідати
  • Павло Б вирішує відповісти і посилає свої медіа потоки Павлу А
  • … Renegotiation ...
  • PROFIT!
Головна відмінність — у застосуванні renegotiation на клієнта.

Давайте напишемо код клієнтів.

Перша частина — ініціалізація WebSDK і логін. Для двох сторін вона буде ідентична.

var vox = VoxImplant.getInstance();
vox.init({micRequired: true,
videoSupport:true,
progressTone:true
});
vox.addEventListener. (VoxImplant.Events.SDKReady, function(){
vox.connect();
});
var call;
vox.addEventListener. (VoxImplant.Events.ConnectionEstablished,function(){
vox.showLocalVideo(true);
vox.login(settings.users[0].name+"@"+settings.app_name+"."+settings.account_name+".voximplant.com",settings.users[0].pass);
vox.addEventListener. (VoxImplant.Events.AuthResult,function(e){

});
});

Далі змусимо код викликає боку показати власне відео на весь екран.

vox.showLocalVideo(true);
var localvideo = document.querySelector('#voximplantlocalvideo');

document.querySelector('.it_remote_video').appendChild(localvideo);
localvideo.style.height = "100%";

localvideo.play(); //дуже важливо викликати play після переміщення, інакше біль і баги

А коли нам з власної сигналізації (про це пізніше) прийде інформація про прийняття дзвінка, покажемо там відео приймаючої сторони, а своє відео приберемо в кут.

call.addEventListener. (VoxImplant.CallEvents.MessageReceived,function(e){
if(e.text=="CONNECTED"){
document.querySelector('.it_local_video').style.display = "block";
document.querySelector('.it_local_video').appendChild(localvideo);
document.querySelector('.it_connecting').style.display = "ні";
localvideo.style.height = "140px";
localvideo.style.marginLeft = "-40px";
localvideo.play();
var remotevideo = document.getElementById(call.getVideoElementId());

document.querySelector('.it_remote_video').appendChild(remotevideo);
remotevideo.style.height = "100%";
remotevideo.removeAttribute("height");
remotevideo.removeAttribute("width");


remotevideo.play();
}
});

Ну і змусимо дзвонити другій стороні.

call = vox.call(settings.users[1].name,true);

Тепер друга сторона.

Ініціалізацію вставимо від першого клієнта.

Тепер нам потрібно хитро прийняти виклик. Ми не будемо передавати звук і відео.

Тепер напишемо код прийому дзвінка.З точки зору SDK це буде автовідповідь.

vox.addEventListener. (VoxImplant.Events.IncomingCall,function(e){
e.call.sendAudio(false);
document.querySelector('.callpopup').style.display = 'block';
call = e.call;
call.answer();
call.addEventListener. (VoxImplant.CallEvents.Connected,function () {
call.mutePlayback();
var remotevideo = document.getElementById(call.getVideoElementId());
document.querySelector('.it_remote_video').appendChild(remotevideo);
remotevideo.style.height = "100%";
remotevideo.removeAttribute("height");
remotevideo.removeAttribute("width");
remotevideo.play();
});
call.addEventListener. (VoxImplant.CallEvents.Disconnected,cancelCall);
call.addEventListener. (VoxImplant.CallEvents.Disconnected,Failed);

})

Зверніть увагу, що ми глушимо звук від зухвалої сторони. Трохи пізніше це допоможе нам швидше почати розмову.

Тепер ми побачимо викликає бік. Залишилося описати кнопки «Відповісти» і «Відбій».

Почнемо з «Відбою»:

function cancelCall() {
if(typeof call!="undefined")
call.hangup();
document.querySelector('.it_remote_video').removeChild(document.querySelector('.it_remote_video').childNodes[0]);
document.querySelector('.it_connecting').style.display = "block";
document.querySelector('.it_exit_link').style.marginLeft = '-110px';
document.querySelector('.it_start_link').style.display = 'block';
document.querySelector('.callpopup').style.display = 'none';
document.querySelector('.it_local_video').style.display = 'none';
}

Кнопка «Відповісти» дивовижна. В її оброблювачі міститься рівно половина магії для роботи приклад. Як тільки користувач натисне її, ми зробимо підключення аудіо і відео потоку до sdk і виконаємо renegotiation.

function answerCall(){
document.querySelector('.it_exit_link').style.marginLeft = '-40px';
document.querySelector('.it_start_link').style.display = 'none';
vox.showLocalVideo(true);
var localvideo = document.querySelector('#voximplantlocalvideo');
document.querySelector('.it_local_video').appendChild(localvideo);
document.querySelector('.it_local_video').style.display = 'block';
document.querySelector('.it_connecting').style.display = "ні";
localvideo.style.height = "140px";
localvideo.style.marginLeft = "-40px";
localvideo.play();
call.unmutePlayback();
call.sendAudio(true);
call.sendVideo(true);
call.sendMessage('CONNECTED');
}

Посилання на репозитарій з готовим проектом → github.com/voximplant/demo_callstats.io
Для того щоб розгорнути його, виконайте:

npm install
npm start

В процесі вам знадобиться ввести вашapi_key і account_id
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.