Создание видеочата с помощью Node.js + Socket.io + WebRTC

от автора

Сегодня, специально к старту нового потока по веб-разработке, поделимся с вами туториалом, из которого вы узнаете, как создать видеочат с помощью JavaScript и NodeJS. Также вы научитесь использовать PeerJS, WebRTC и Socket.io.


Здесь вы можете увидеть живой пример приложения, которое вы будете создавать.

Подготовка к проекту

Вот что вам понадобится:

  • NodeJS: посетите официальный веб-сайт Node.js, чтобы загрузить и установить Node;

  • NPM: программа NPM устанавливается на ваш компьютер при установке Node.js.

Настройка проекта

Весь код этого проекта можно найти в репозитории GitHub.

  1. Создайте пустой каталог с именем video-chat-app.

  2. Откройте консоль, перейдите в наш новый каталог и запустите npm init.

  3. Заполните необходимую информацию для инициализации нашего проекта.

  4. Запустите npm install express ejs socket.io uuid peer. Команда установит все зависимости, необходимые для создания этого приложения.

  5. А также в качестве dev-зависимости установите Nodemon. Нужно выполнить npm install-dev nodemon. Это установит nodemon как dev-зависимость.

  6. Создайте файл server.js — в этом файле будет храниться вся ваша серверная логика.

Теперь, когда у вас настроен наш проект, вы можете приступить к созданию приложения!

Создание сервера (с Express JS)

Первое, что вам нужно сделать, — это запустить ваш сервер. Мы собираемся использовать для этого Express. Express — это минималистичный веб-фреймворк для Node.js. Express позволяет очень легко создавать и запускать веб-сервер с помощью Node.

Давайте создадим шаблонный файл начального приложения Express.

// server.js const express = require(“express”); const app = express(); const server = require(“http”).Server(app); app.get(“/”, (req, res) => {     res.status(200).send(“Hello World”); }); server.listen(3030);

Теперь ваш сервер запущен, вы можете протестировать его, запустив:

> nodemon server.js

Теперь откройте свой браузер и перейдите по адресу: localhost:3000, вы должны увидеть Hello World.

Создание первой страницы

Вместо того чтобы выводить текст, когда кто-то посещает ваш корневой маршрут, вы хотели бы присылать HTML. Для этого нужно использовать EJS (встроенный JavaScript). EJS — это язык шаблонов.

Чтобы использовать EJS в Express, вам нужно настроить ваш шаблонизатор. Для настройки добавьте эту строку кода в файл server.js.

app.set(‘view engine’, ‘ejs’)

Доступ к EJS по умолчанию осуществляется в каталоге views. Теперь создайте новую папку views в каталоге. В этой папке добавьте файл с именем room.ejs. Пока что думайте о нашем файле room.ejs как о HTML-файле.

Вот как выглядит ваша файловая структура:

|-- video-chat-app    |-- views       |-- room.ejs    |-- package.json    |-- server.js

Теперь добавьте HTML-код в файл room.ejs.

Как только вы скопируете приведённый выше код, нужно немного поменять app.js:

app.get(‘/’, function (req, res) {  // OLD CODE  res.status(200).send("Hello World"); })

Выше приведён старый код, в котором вы отправляете клиенту текст «Hello World!». Вместо этого вы хотите отправить файл room.ejs:

app.get(‘/’, function (req, res) {  // NEW CODE  res.render(‘room’); })

Теперь откройте браузер и перейдите по адресу: localhost:3030, и вы увидите, что отображается файл room.ejs!

Добавление CSS

Выглядит не очень хорошо, правда? Это потому, что в вашем проекте нет стилей. Итак, добавьте немного CSS.

Нам нужно будет добавить новую папку в проект под названием public. В этой папке создайте файлы style.css и script.js. Вот ваша новая файловая структура:

|-- weather-app    |-- views       |-- index.ejs    |-- public       |-- style.css       |-- script.js    |-- package.json    |-- server.js

Express не даёт доступа к этому файлу по умолчанию, поэтому вам нужно открыть его с помощью следующей строки кода:

app.use(express.static(‘public’));

Этот код позволяет вам получить доступ ко всем статическим файлам в папке “public”. Наконец, вам нужен CSS. Поскольку это не курс по CSS, я не буду вдаваться в подробности, но если вы хотите использовать мои стили, вы можете скопировать их отсюда.

После того как вы добавили CSS, вы можете посетить: localhost:3030. Вы заметите, что приложение выглядит немного лучше.

Настройка комнат

К настоящему моменту ваш файл server.js должен выглядеть так:

У вас есть один GET-роут и запуск сервера. Однако, чтобы ваше приложение работало, нужно всякий раз, когда новый пользователь посещает ваш роут по умолчанию, перенаправлять его на уникальный URL-адрес. Следует использовать библиотеку uuid для создания случайного уникального URL-адреса для каждой комнаты.

UUID — это библиотека javascript, которая позволяет вам создавать уникальные идентификаторы. В вашем приложении вы будете использовать uuid версии 4 для создания уникального URL. Но сначала импортируйте uuid в server.js. 

const { v4: uuidv4 } = require("uuid");

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

app.get(“/”, (req, res) => {     res.redirect(`/${uuidv4()}`); });

И, прежде чем вы протестируете это, я также хотел добавить страницу для каждой уникальной комнаты, и вы передадите текущий URL этой странице.

app.get(“/:room”, (req, res) => {     res.render(“room”, { roomId: req.param.room }); });

Вы передали roomId в room.ejs на этом закончили настройку ваших комнат. А теперь, если вы посетите localhost:3030, вы будете перенаправлены на уникальный URL.

Добавление видео пользователя

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

Итак, вот что необходимо сделать: нужно получить видеопоток, а затем добавить этот поток в элемент видео.

let myVideoStream; const videoGrid = document.getElementById("video-grid"); const myVideo = document.createElement("video"); myVideo.muted = true; navigator.mediaDevices.getUserMedia({     audio: true,     video: true, }) .then((stream) => {     myVideoStream = stream;     addVideoStream(myVideo, stream); });

Теперь создайтем функцию addVideoStream, которая добавит поток к видеоэлементу.

const addVideoStream = (video, stream) => {     video.srcObject = stream;     video.addEventListener("loadedmetadata", () => {        video.play();        videoGrid.append(video);     }); };

Этот код добавит пользовательский поток к видеоэлементу. Вы можете проверить это, посетив localhost:3030, и вы увидите всплывающее окно с видео 

Добавление возможности разрешить другим пользователям транслировать свои видео в потоковом режиме.

Пришло время использовать Socket.io и PeerJS. Для тех, кто не знает, Socket.io позволяет взаимодействовать серверу и клиенту в режиме реального времени.  PeerJS позволяют реализовать WebRTC.

Сначала импортируйте socket.io и peerjs в server.js и прослушайте событие соединения.

// server.js const express = require(“express”); const app = express(); const server = require(“http”).Server(app); const { v4: uuidv4 } = require(“uuid”); app.set(“view engine”, “ejs”); const io = require(“socket.io”)(server); const { ExpressPeerServer } = require(“peer”); const peerServer = ExpressPeerServer(server, {     debug: true, }); app.use(“/peerjs”, peerServer); app.use(express.static(“public”)); app.get(“/”, (req, res) => {     res.redirect(`/${uuidv4()}`); }); app.get(“/:room”, (req, res) => {     res.render(“room”, { roomId: req.param.room }); }); io.on(“connection”, (socket) => {     socket.on(“join-room”, (roomId, userId) => {     socket.join(roomId);     socket.to(roomId).broadcast.emit(“user-connected”, userId);     }); }); server.listen(3030);

Теперь ваш сервер прослушивает событие присоединения к комнате. Далее настройте ваш script.js.

// public/script.js const socket = io(“/”); const videoGrid = document.getElementById(“video-grid”); const myVideo = document.createElement(“video”); myVideo.muted = true; var peer = new Peer(undefined, {   path: “/peerjs”,   host: “/”,   port: “3030”, }); let myVideoStream; navigator.mediaDevices   .getUserMedia({   audio: true,   video: true, }) .then((stream) => {   myVideoStream = stream;   addVideoStream(myVideo, stream);   peer.on(“call”, (call) => {     call.answer(stream);     const video = document.createElement(“video”);     call.on(“stream”, (userVideoStream) => {       addVideoStream(video, userVideoStream);       });     });   socket.on(“user-connected”, (userId) => {       connectToNewUser(userId, stream);   }); }); const connectToNewUser = (userId, stream) => {   const call = peer.call(userId, stream);   const video = document.createElement(“video”);   call.on(“stream”, (userVideoStream) => {       addVideoStream(video, userVideoStream);   }); }; peer.on(“open”, (id) => {     socket.emit(“join-room”, ROOM_ID, id); }); const addVideoStream = (video, stream) => {   video.srcObject = stream;   video.addEventListener(“loadedmetadata”, () => {     video.play();     videoGrid.append(video);   }); };

Теперь, если в комнату войдёт новый пользователь, вы увидите его видео.

Создание пользовательского интерфейса

С видеочастью закончили. А теперь займитесь стилизацией. Но сначала добавьте контент в файл room.ejs. (Добавьте CDN font-awesome внутри тега head.)

// views/room.ejs <body>   <div class="header">     <div class="logo">       <h3>Video Chat</h2>     </div>   </div>   <div class="main">     <div class="main__left">       <div class="videos__group">         <div id="video-grid"></div>       </div>       <div class="options">         <div class="options__left">           <div class="options__button">             <i class="fa fa-video-camera" aria-hidden="true"></i>           </div>         <div class="options__button">             <i class="fa fa-microphone" aria-hidden="true"></i>         </div>        </div>        <div class="options__right">          <div class="options__button background__red">            <i class="fa fa-phone" aria-hidden="true"></i>          </div>        </div>      </div>     </div>     <div class="main__right">       <div class="main__chat_window">         <ul class="messages"></ul>      </div>      <div class="main__message_container">        <input id="chat_message" type="text" placeholder="Type message here...">        <div class="options__button">          <i class="fa fa-plus" aria-hidden="true"></i>        </div>      </div>     </div>   </div> </body>

Затем откройте файл style.css и добавьте немного CSS.

@import url(“https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap"); :root {   — main-darklg: #1d2635;   — main-dark: #161d29;   — primary-color: #2f80ec;   — main-light: #eeeeee;   font-family: “Poppins”, sans-serif; } * {   margin: 0;   padding: 0; } .header {   display: flex;   justify-content: center;   align-items: center;   height: 8vh;   width: 100%;   background-color: var( — main-darklg); } .logo > h3 {     color: var( — main-light); } .main {   overflow: hidden;   height: 92vh;   display: flex; } .main__left {   flex: 0.7;   display: flex;   flex-direction: column; } .videos__group {   flex-grow: 1;   display: flex;   justify-content: center;   align-items: center;   padding: 1rem;   background-color: var( — main-dark); } video {   height: 300px;   border-radius: 1rem;   margin: 0.5rem;   width: 400px;   object-fit: cover;   transform: rotateY(180deg);   -webkit-transform: rotateY(180deg);   -moz-transform: rotateY(180deg); } .options {   padding: 1rem;   display: flex;   background-color: var( — main-darklg); } .options__left {     display: flex; } .options__right {     margin-left: auto; } .options__button {   display: flex;   justify-content: center;   align-items: center;   background-color: var( — primary-color);   height: 50px;   border-radius: 5px;   color: var( — main-light);   font-size: 1.2rem;   width: 50px;   margin: 0 0.5rem; } .background__red {     background-color: #f6484a; } .main__right { flex: 0.3;     background-color: #242f41; } .main__chat_window {     flex-grow: 1; } .main__message_container {   padding: 1rem;   display: flex;   align-items: center;   justify-content: center; } .main__message_container > input {   height: 50px;   flex: 1;   border-radius: 5px;   padding-left: 20px;   border: none; } #video-grid {   display: flex;   justify-content: center;   flex-wrap: wrap; }

Вот и всё! Поздравляем, вы успешно создали видеочат! Теперь вы можете развернуть его на Heroku и показать его всему миру. Демо и исходный код.

Это лишь небольшой пример того, какие вещи может делать веб-разработчик, причем в одиночку. Сделать just for fun экспорт музыки в Spotify и получить известность, пока огромная компания долго думает над решением задачи — без проблем. За один вечер набросать и выкатить расширение для браузера, которое упростит жизнь миллионам пользователей — тоже по силам. На что еще способна веб-разработка — зависит только от фантазии программиста. Приходите учиться, чтобы освоить дзюцу веб-разработки и стать настоящим самураем интернета.

Узнайте, как прокачаться в других специальностях или освоить их с нуля:

Другие профессии и курсы

ссылка на оригинал статьи https://habr.com/ru/company/skillfactory/blog/551008/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *