Представим ситуацию: у нас есть чат-платформа и нам необходимо прикрутить к ней видеозвонки, то есть в онлайне сидит некий Вася и он хочет позвонить Пете, для реализации такой фичи нам понадобится технология WebSocket.
Что ж, давайте поднимем наш WebSocket сервер, нам в этом поможет node.js;
Создадим файл sockets.js и запишем туда код сокет сервера:
const WebSocketServer = require('websocket').server; const http = require('http'); const server = http.createServer(function(request, response) { //здесь мы ничего не пишем,потому что мы используем сокеты,а не http }); server.listen(1337, function() {}); // создаем вебсокет сервер const wsServer = new WebSocketServer({ httpServer: server }); wsServer.on('request', function(request) { let connection = request.accept(null, request.origin); //принимаем подключение к сокету })
Создадим файл index.html и запишем туда код для открытия сокет-соединения:
<video autoplay muted height='300' width='300' style="position:fixed;bottom:0;left:0;z-index: 9999;" src="" id='my'> </video> <!-- наше видео --> <video autoplay height='300' width='300' style="position:fixed;bottom:0;left:300px;z-index: 999999;" src="" id='not_my'> </video> <!--видео нашего собеседника-->
Теперь создадим и подключим файл script.js к нашему html файлу:
let connection = new WebSocket('ws://127.0.0.1:1337');//подключаемся к нашему сокет-серверу connection.onopen = function(){ //если вам необходимо,можете отправлять какие-либо данные на сокет при его открытии } connection.onmessage = function(message){ //функция которая будет выполняться при приходе сообщения от сокета } connection.onerror = function (error) { console.error(error) //функция которая выполнится,если будет ошибка соединения };
Итак, вернемся к нашему Васе и Пете

Это начальный этап на котором Вася с Петей просто обмениваются JSON, о том будем ли принимать звонок или нет.То есть при заходе на нашу страницу мы обязательно должны открывать WebSocket соединение для связи с нашим сокет сервером.
- Мы шлем сначала на сокет сервер JSON с тем, что мы хотим позвонить Пете с аккаунта Васи
connection.send(JSON.stringify({ //данные для инициализации })) - На сокет сервере мы должны этот JSON принять, после того как мы получили request, мы на наш сервер навешиваем событие message:
connection.on('message',function(message){ //можем работать с message и отсылать кому угодно,но прежде переведем все из JSON в JS let self = JSON.parse(message.utf8Data); })
Пообщавшись и решив, что оба пользователя готовы к разговору, мы должны разобраться как работает видеосвязь в браузере, в js встроен модуль для этого — RTCPeerConnection

Нам необходимо открыть RTCPeerConnection, с помощью которого мы сможем сгененрировать offer и отправить его нужному нам пользователю опять же через наш сокет-сервер, который получив его сгенерирует нам answer и отправит обратно, после чего мы начинаем обмениваться ice пакетами, в которых содержится информация об окружении данного компьютера, которая необходима для успешного установления видеосвязи.
Генерируем и отправляем offer
var pc = new RTCPeerConnection(); var peerConnectionConfig = { iceServers: [ { urls: 'stun:stun.l.google.com:19302' } ] } pc.onicecandidate = function (event) { console.log('new ice candidate', event.candidate); if (event.candidate !== null) { connection.send(JSON.stringify({ //отправляем json и ice пакеты })) } }; navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; navigator.getUserMedia({video: true,audio:true}, function(stream) { // Добавление локального потока не вызовет onaddstream обратного вызова, // так называют его вручную. var my_video = document.getElementById('my') my_video.srcObject = stream pc.onaddstream = e => { document.getElementById('not_my').srcObject = e.stream; console.log('not stream is added') } pc.addStream(stream); pc.createOffer(function(offer) { pc.setLocalDescription(offer, function() { //отправляем наш offer на сокет })) }, e=> console.log(e)); }, e=> console.log(e)); },function (){console.warn("Error getting audio stream from getUserMedia")}); // функция помощник function endCall() { var videos = document.getElementsByTagName("video"); for (var i = 0; i < videos.length; i++) { videos[i].pause(); } pc.close(); } function error(err) { endCall(); }
Обрабатываем offer и генерируем answer
var pc = new RTCPeerConnection();//создаем connection var peerConnectionConfig = { //конфигурация ice server iceServers: [ { urls: 'stun:stun.l.google.com:19302' } ] } pc.onicecandidate = function (event) { console.log('new ice candidate', event.candidate); if (event.candidate !== null) { //отправляем ice пакеты } }; navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; navigator.getUserMedia({video: true,audio:true}, function(stream) {//подключаем у пользователя видеосвязь и аудиосвязь и втыкаем ее на страницу var my_video = document.getElementById('my') my_video.srcObject = stream console.log('stream is added while offering') pc.onaddstream = e => { console.log('not my stream is added while offering') document.getElementById('not_my').srcObject = e.stream; } pc.addStream(stream); pc.setRemoteDescription(new RTCSessionDescription(data.offer), function() { pc.createAnswer(function(answer) { pc.setLocalDescription(answer, function() { //отправляем ответ }, e => console.log(e)); }, e => console.log(e)); }, e => console.log(e)); },function (){console.warn("Error getting audio stream from getUserMedia")}); } }
Принимаем answer и создаем видеопоток
pc.setRemoteDescription(new RTCSessionDescription(data.answer), function() { }, error);
И последнее что нам нужно сделать — обработать ice пакеты
pc.addIceCandidate(new RTCIceCandidate(ice))//тут ice - тот,который пришел нам от пользователя
ссылка на оригинал статьи https://habr.com/ru/post/502726/
Добавить комментарий