Учебники

WebRTC — видео демо

В этой главе мы собираемся создать клиентское приложение, которое позволит двум пользователям на разных устройствах общаться через WebRTC. Наше приложение будет иметь две страницы. Один для входа в систему, а другой для вызова другого пользователя.

Страница авторизации

Две страницы будут тегами div . Большая часть ввода осуществляется через простые обработчики событий.

Страница для звонков.

Сигнальный сервер

Чтобы создать соединение WebRTC, клиенты должны иметь возможность передавать сообщения без использования однорангового соединения WebRTC. Здесь мы будем использовать HTML5 WebSockets — двунаправленное сокетное соединение между двумя конечными точками — веб-сервером и веб-браузером. Теперь давайте начнем использовать библиотеку WebSocket. Создайте файл server.js и вставьте следующий код —

//require our websocket library 
var WebSocketServer = require('ws').Server; 

//creating a websocket server at port 9090 
var wss = new WebSocketServer({port: 9090});
  
//when a user connects to our sever 
wss.on('connection', function(connection) { 
   console.log("user connected"); 
	
   //when server gets a message from a connected user 
   connection.on('message', function(message) { 
      console.log("Got message from a user:", message); 
   }); 
	
   connection.send("Hello from server");
});

Первая строка требует библиотеки WebSocket, которую мы уже установили. Затем мы создаем сервер сокетов на порту 9090. Затем мы прослушиваем событие подключения . Этот код будет выполнен, когда пользователь устанавливает соединение WebSocket с сервером. Затем мы слушаем любые сообщения, отправленные пользователем. Наконец, мы отправляем ответ подключенному пользователю, говоря «Привет с сервера».

На нашем сервере сигнализации мы будем использовать имя пользователя на основе строки для каждого соединения, чтобы мы знали, куда отправлять сообщения. Давайте немного изменим наш обработчик соединения —

connection.on('message', function(message) { 
   var data; 
	
   //accepting only JSON messages 
   try { 
      data = JSON.parse(message); 
   } catch (e) { 
      console.log("Invalid JSON"); 
      data = {}; 
   } 
});

Таким образом, мы принимаем только сообщения JSON. Далее нам нужно где-то хранить всех подключенных пользователей. Мы будем использовать простой объект Javascript для него. Изменить верх нашего файла —

//require our websocket library 
var WebSocketServer = require('ws').Server; 

//creating a websocket server at port 9090 
var wss = new WebSocketServer({port: 9090}); 

//all connected to the server users 
var users = {};

Мы собираемся добавить поле типа для каждого сообщения от клиента. Например, если пользователь хочет войти, он отправляет сообщение типа входа . Давайте определим это —

connection.on('message', function(message) { 
   var data; 
	
   //accepting only JSON messages 
   try { 
      data = JSON.parse(message);
   } catch (e) { 
      console.log("Invalid JSON"); 
      data = {}; 
   } 
	
   //switching type of the user message 
   switch (data.type) { 
      //when a user tries to login 
      case "login": 
         console.log("User logged:", data.name); 
			
         //if anyone is logged in with this username then refuse 
         if(users[data.name]) { 
            sendTo(connection, { 
               type: "login", 
               success: false 
            }); 
         } else { 
            //save user connection on the server 
            users[data.name] = connection; 
            connection.name = data.name; 
				
            sendTo(connection, { 
               type: "login", 
               success: true 
            }); 
         } 
			
         break;
			
      default: 
         sendTo(connection, { 
            type: "error", 
            message: "Command no found: " + data.type 
         }); 
			
         break;
   }  
});					 

Если пользователь отправляет сообщение с типом логина , мы —

  • Проверьте, если кто-то уже вошел в систему с этим именем пользователя

  • Если это так, то сообщите пользователю, что он не вошел в систему

  • Если никто не использует это имя пользователя, мы добавляем имя пользователя в качестве ключа к объекту подключения.

  • Если команда не распознана, мы отправляем ошибку.

Проверьте, если кто-то уже вошел в систему с этим именем пользователя

Если это так, то сообщите пользователю, что он не вошел в систему

Если никто не использует это имя пользователя, мы добавляем имя пользователя в качестве ключа к объекту подключения.

Если команда не распознана, мы отправляем ошибку.

Следующий код является вспомогательной функцией для отправки сообщений в соединение. Добавьте его в файл server.js

function sendTo(connection, message) { 
   connection.send(JSON.stringify(message)); 
}

Когда пользователь отключается, мы должны очистить его соединение. Мы можем удалить пользователя при возникновении события закрытия . Добавьте следующий код в обработчик соединения

connection.on("close", function() { 
   if(connection.name) { 
      delete users[connection.name]; 
   } 
});

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

case "offer": 
   //for ex. UserA wants to call UserB 
   console.log("Sending offer to: ", data.name);
	
   //if UserB exists then send him offer details 
   var conn = users[data.name]; 
	
   if(conn != null) { 
      //setting that UserA connected with UserB 
      connection.otherName = data.name; 
		
      sendTo(conn, { 
         type: "offer",
         offer: data.offer, 
         name: connection.name 
      }); 
		
   }  
	
   break;

Во-первых, мы получаем соединение с пользователем, которого пытаемся вызвать. Если он существует, мы отправляем ему детали предложения . Мы также добавляем otherName к объекту соединения . Это сделано для простоты поиска позже.

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

case "answer": 
   console.log("Sending answer to: ", data.name); 
	
   //for ex. UserB answers UserA 
   var conn = users[data.name]; 
	
   if(conn != null) { 
      connection.otherName = data.name; 
		
      sendTo(conn, { 
         type: "answer", 
         answer: data.answer 
      }); 
   } 
	
   break;

Заключительная часть — обработка кандидата ICE между пользователями. Мы используем ту же технику, просто передавая сообщения между пользователями. Основное отличие состоит в том, что сообщения-кандидаты могут появляться несколько раз на пользователя в любом порядке. Добавьте обработчик кандидата

case "candidate": 
   console.log("Sending candidate to:",data.name); 
   var conn = users[data.name];
	
   if(conn != null) { 
      sendTo(conn, { 
         type: "candidate", 
         candidate: data.candidate 
      }); 
   } 
	
   break;

Чтобы позволить нашим пользователям отключаться от другого пользователя, мы должны реализовать функцию зависания. Он также скажет серверу удалить все пользовательские ссылки. Добавьте обработчик отпуска

case "leave": 
   console.log("Disconnecting from", data.name); 
   var conn = users[data.name]; 
   conn.otherName = null; 
	
   //notify the other user so he can disconnect his peer connection 
   if(conn != null) { 
      sendTo(conn, { 
         type: "leave" 
      }); 
   } 
	
   break;

Это также отправит другому пользователю событие ухода, чтобы он мог соответствующим образом отключить одноранговое соединение. Также следует разобраться со случаем, когда пользователь сбрасывает соединение с сервера сигнализации. Давайте изменим наш близкий обработчик —

connection.on("close", function() { 

   if(connection.name) { 
      delete users[connection.name]; 
		
      if(connection.otherName) { 
         console.log("Disconnecting from ", connection.otherName); 
         var conn = users[connection.otherName]; 
         conn.otherName = null;  
			
         if(conn != null) { 
            sendTo(conn, { 
               type: "leave" 
            });
         }
			
      } 
   } 
}); 

Ниже приведен полный код нашего сервера сигнализации.

//require our websocket library 
var WebSocketServer = require('ws').Server; 

//creating a websocket server at port 9090 
var wss = new WebSocketServer({port: 9090}); 

//all connected to the server users 
var users = {};
  
//when a user connects to our sever 
wss.on('connection', function(connection) {
  
   console.log("User connected");
	
   //when server gets a message from a connected user 
   connection.on('message', function(message) { 
	
      var data; 
		
      //accepting only JSON messages 
      try { 
         data = JSON.parse(message); 
      } catch (e) { 
         console.log("Invalid JSON"); 
         data = {}; 
      }
		
      //switching type of the user message 
      switch (data.type) { 
         //when a user tries to login
         case "login": 
            console.log("User logged", data.name); 
				
            //if anyone is logged in with this username then refuse 
            if(users[data.name]) { 
               sendTo(connection, { 
                  type: "login", 
                  success: false 
               }); 
            } else { 
               //save user connection on the server 
               users[data.name] = connection; 
               connection.name = data.name; 
					
               sendTo(connection, { 
                  type: "login", 
                  success: true 
               }); 
            } 
				
            break;
				
         case "offer": 
            //for ex. UserA wants to call UserB 
            console.log("Sending offer to: ", data.name);
				
            //if UserB exists then send him offer details 
            var conn = users[data.name]; 
				
            if(conn != null) { 
               //setting that UserA connected with UserB 
               connection.otherName = data.name; 
					
               sendTo(conn, { 
                  type: "offer", 
                  offer: data.offer, 
                  name: connection.name 
               }); 
            }
				
            break;
				
         case "answer": 
            console.log("Sending answer to: ", data.name); 
            //for ex. UserB answers UserA 
            var conn = users[data.name]; 
				
            if(conn != null) { 
               connection.otherName = data.name; 
               sendTo(conn, { 
                  type: "answer", 
                  answer: data.answer 
               }); 
            } 
				
            break; 
				
         case "candidate": 
            console.log("Sending candidate to:",data.name); 
            var conn = users[data.name];
				
            if(conn != null) { 
               sendTo(conn, { 
                  type: "candidate", 
                  candidate: data.candidate 
               }); 
            } 
				
            break;
				
         case "leave": 
            console.log("Disconnecting from", data.name); 
            var conn = users[data.name]; 
            conn.otherName = null; 
				
            //notify the other user so he can disconnect his peer connection 
            if(conn != null) {
               sendTo(conn, { 
                  type: "leave" 
              }); 
            }
				
            break;
				
         default: 
            sendTo(connection, { 
               type: "error", 
               message: "Command not found: " + data.type 
            }); 
				
            break; 
      }
		
   }); 
	
   //when user exits, for example closes a browser window 
   //this may help if we are still in "offer","answer" or "candidate" state 
   connection.on("close", function() { 
	
      if(connection.name) { 
         delete users[connection.name]; 
			
         if(connection.otherName) { 
            console.log("Disconnecting from ", connection.otherName); 
            var conn = users[connection.otherName]; 
            conn.otherName = null;
				
            if(conn != null) { 
               sendTo(conn, { 
                  type: "leave" 
               }); 
            }
         } 
      }
		
   });  
	
   connection.send("Hello world");  
});
  
function sendTo(connection, message) { 
   connection.send(JSON.stringify(message)); 
}

Клиентское приложение

Один из способов проверить это приложение — открыть две вкладки браузера и попытаться вызвать друг друга.

Прежде всего, нам нужно установить библиотеку начальной загрузки . Bootstrap — это интерфейс для разработки веб-приложений. Вы можете узнать больше на http://getbootstrap.com/. Создайте папку с именем, например, «видеочат». Это будет наша корневая папка приложения. Внутри этой папки создайте файл package.json (он необходим для управления зависимостями npm) и добавьте следующее:

{ 
   "name": "webrtc-videochat", 
   "version": "0.1.0", 
   "description": "webrtc-videochat", 
   "author": "Author", 
   "license": "BSD-2-Clause" 
}

Затем запустите npm install bootstrap . Это установит библиотеку начальной загрузки в папку videochat / node_modules .

Теперь нам нужно создать простую HTML-страницу. Создайте файл index.html в корневой папке со следующим кодом —

<html> 
 
   <head> 
      <title>WebRTC Video Demo</title>
      <link rel = "stylesheet" href = "node_modules/bootstrap/dist/css/bootstrap.min.css"/>
   </head>
	
   <style>
	
      body { 
         background: #eee; 
         padding: 5% 0; 
      } 
		
      video { 
         background: black; 
         border: 1px solid gray; 
      }
		
      .call-page { 
         position: relative; 
         display: block; 
         margin: 0 auto; 
         width: 500px; 
         height: 500px; 
      } 
		
      #localVideo { 
         width: 150px; 
         height: 150px; 
         position: absolute; 
         top: 15px; 
         right: 15px; 
      }
		
      #remoteVideo { 
         width: 500px; 
         height: 500px; 
      }
		
   </style>
	
   <body>
	
   <div id = "loginPage" class = "container text-center"> 
	
      <div class = "row"> 
         <div class = "col-md-4 col-md-offset-4">
			
            <h2>WebRTC Video Demo. Please sign in</h2> 
            <label for = "usernameInput" class = "sr-only">Login</label> 
            <input type = "email" id = "usernameInput" c
               lass = "form-control formgroup" placeholder = "Login" 
               required = "" autofocus = ""> 
            <button id = "loginBtn" class = "btn btn-lg btn-primary btnblock">
               Sign in</button>
				
         </div> 
      </div> 
		
   </div>
	
   <div id = "callPage" class = "call-page"> 
      <video id = "localVideo" autoplay></video> 
      <video id = "remoteVideo" autoplay></video>
		
      <div class = "row text-center"> 
         <div class = "col-md-12"> 
            <input id = "callToUsernameInput" type = "text"
               placeholder = "username to call" /> 
            <button id = "callBtn" class = "btn-success btn">Call</button> 
            <button id = "hangUpBtn" class = "btn-danger btn">Hang Up</button> 
         </div>	
      </div> 
		
   </div>
	
   <script src = "client.js"></script> 
	
   </body>
	
</html>		  

Эта страница должна быть вам знакома. Мы добавили файл начальной загрузки css. Мы также определили две страницы. Наконец, мы создали несколько текстовых полей и кнопок для получения информации от пользователя. Вы должны увидеть два видеоэлемента для локальных и удаленных видеопотоков. Обратите внимание, что мы добавили ссылку на файл client.js .

Теперь нам нужно установить соединение с нашим сервером сигнализации. Создайте файл client.js в корневой папке со следующим кодом —

//our username 
var name; 
var connectedUser;
  
//connecting to our signaling server 
var conn = new WebSocket('ws://localhost:9090');
  
conn.onopen = function () { 
   console.log("Connected to the signaling server"); 
};
  
//when we got a message from a signaling server 
conn.onmessage = function (msg) { 
   console.log("Got message", msg.data);
	
   var data = JSON.parse(msg.data);
	
   switch(data.type) { 
      case "login": 
         handleLogin(data.success);
         break; 
      //when somebody wants to call us 
      case "offer": 
         handleOffer(data.offer, data.name); 
         break; 
      case "answer": 
         handleAnswer(data.answer); 
         break; 
      //when a remote peer sends an ice candidate to us 
      case "candidate": 
         handleCandidate(data.candidate); 
         break; 
      case "leave": 
         handleLeave(); 
         break; 
      default: 
         break; 
   } 
};
  
conn.onerror = function (err) { 
   console.log("Got error", err); 
};
  
//alias for sending JSON encoded messages 
function send(message) { 
   //attach the other peer username to our messages 
   if (connectedUser) { 
      message.name = connectedUser; 
   } 
	
   conn.send(JSON.stringify(message)); 
};

Теперь запустите наш сервер сигнализации через сервер узлов . Затем внутри корневой папки запустите статическую команду и откройте страницу в браузере. Вы должны увидеть следующий вывод консоли —

Клиентское приложение

Следующим шагом является реализация входа пользователя с уникальным именем пользователя. Мы просто отправляем имя пользователя на сервер, который затем сообщает нам, занято оно или нет. Добавьте следующий код в ваш файл client.js

//****** 
//UI selectors block 
//****** 

var loginPage = document.querySelector('#loginPage'); 
var usernameInput = document.querySelector('#usernameInput'); 
var loginBtn = document.querySelector('#loginBtn'); 

var callPage = document.querySelector('#callPage'); 
var callToUsernameInput = document.querySelector('#callToUsernameInput');
var callBtn = document.querySelector('#callBtn'); 

var hangUpBtn = document.querySelector('#hangUpBtn');
  
//hide call page 
callPage.style.display = "none"; 
 
// Login when the user clicks the button 
loginBtn.addEventListener("click", function (event) { 
   name = usernameInput.value; 
	
   if (name.length > 0) { 
      send({ 
         type: "login", 
         name: name 
      }); 
   } 
	
});
 
function handleLogin(success) { 

   if (success === false) { 
      alert("Ooops...try a different username"); 
   } else { 
      //display the call page if login is successful 
      loginPage.style.display = "none"; 
      callPage.style.display = "block";  
      //start peer connection 
   } 
};

Во-первых, мы выбираем несколько ссылок на элементы на странице. Мы скрываем страницу вызова. Затем мы добавляем прослушиватель событий на кнопку входа. Когда пользователь щелкает по нему, мы отправляем его имя пользователя на сервер. Наконец, мы реализуем обратный вызов handleLogin. Если вход был успешным, мы показываем страницу вызова и начинаем устанавливать одноранговое соединение.

Чтобы начать одноранговое соединение нам нужно —

  • Получить поток с веб-камеры.
  • Создайте объект RTCPeerConnection.

Добавьте следующий код в «блок селекторов пользовательского интерфейса» —

var localVideo = document.querySelector('#localVideo'); 
var remoteVideo = document.querySelector('#remoteVideo');
 
var yourConn; 
var stream;

Изменить функцию handleLogin

function handleLogin(success) { 

   if (success === false) { 
      alert("Ooops...try a different username"); 
   } else { 
      loginPage.style.display = "none"; 
      callPage.style.display = "block";
		  
      //********************** 
      //Starting a peer connection 
      //********************** 
		
      //getting local video stream 
      navigator.webkitGetUserMedia({ video: true, audio: true }, function (myStream) { 
         stream = myStream; 
			
         //displaying local video stream on the page 
         localVideo.src = window.URL.createObjectURL(stream);
			
         //using Google public stun server 
         var configuration = { 
            "iceServers": [{ "url": "stun:stun2.1.google.com:19302" }] 
         }; 
			
         yourConn = new webkitRTCPeerConnection(configuration);
			
         // setup stream listening 
         yourConn.addStream(stream); 
			
         //when a remote user adds stream to the peer connection, we display it 
         yourConn.onaddstream = function (e) { 
            remoteVideo.src = window.URL.createObjectURL(e.stream); 
         };
			
         // Setup ice handling 
         yourConn.onicecandidate = function (event) {
			
            if (event.candidate) { 
               send({ 
                  type: "candidate", 
                  candidate: event.candidate 
               }); 
            } 
				
         };
			
      }, function (error) { 
         console.log(error); 
      }); 
   } 
};

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

Локальный видео поток

Теперь мы готовы инициировать вызов. Сначала мы отправляем предложение другому пользователю. Как только пользователь получает предложение, он создает ответ и начинает торговать кандидатами ICE. Добавьте следующий код в файл client.js

//initiating a call 
callBtn.addEventListener("click", function () { 
   var callToUsername = callToUsernameInput.value; 
	
   if (callToUsername.length > 0) {
	
      connectedUser = callToUsername;
		
      // create an offer
      yourConn.createOffer(function (offer) { 
         send({ 
            type: "offer", 
            offer: offer 
         }); 
			
         yourConn.setLocalDescription(offer); 
			
      }, function (error) { 
         alert("Error when creating an offer"); 
      });  
   } 
});
  
//when somebody sends us an offer 
function handleOffer(offer, name) { 
   connectedUser = name; 
   yourConn.setRemoteDescription(new RTCSessionDescription(offer));
	
   //create an answer to an offer 
   yourConn.createAnswer(function (answer) { 
      yourConn.setLocalDescription(answer); 
		
      send({ 
         type: "answer", 
         answer: answer 
      }); 
		
   }, function (error) { 
      alert("Error when creating an answer"); 
   }); 
};
  
//when we got an answer from a remote user 
function handleAnswer(answer) { 
   yourConn.setRemoteDescription(new RTCSessionDescription(answer));
}; 
 
//when we got an ice candidate from a remote user 
function handleCandidate(candidate) { 
   yourConn.addIceCandidate(new RTCIceCandidate(candidate)); 
};

Мы добавляем обработчик кликов к кнопке Call, которая инициирует предложение. Затем мы реализуем несколько обработчиков, ожидаемых обработчиком onmessage . Они будут обрабатываться асинхронно, пока оба пользователя не установят соединение.

Последний шаг — реализация функции зависания. Это прекратит передачу данных и скажет другому пользователю закрыть вызов. Добавьте следующий код —

//hang up 
hangUpBtn.addEventListener("click", function () { 

   send({ 
      type: "leave" 
   });
	
   handleLeave(); 
});
  
function handleLeave() { 
   connectedUser = null; 
   remoteVideo.src = null; 
	
   yourConn.close(); 
   yourConn.onicecandidate = null; 
   yourConn.onaddstream = null; 
};

Когда пользователь нажимает кнопку Hang Up —

  • Он отправит сообщение «оставить» другому пользователю
  • Это закроет RTCPeerConnection и уничтожит соединение локально

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

позвони и повесь

Ниже приведен весь файл client.js

//our username 
var name; 
var connectedUser;
  
//connecting to our signaling server
var conn = new WebSocket('ws://localhost:9090');
  
conn.onopen = function () { 
   console.log("Connected to the signaling server"); 
};
  
//when we got a message from a signaling server 
conn.onmessage = function (msg) { 
   console.log("Got message", msg.data);
	
   var data = JSON.parse(msg.data); 
	
   switch(data.type) { 
      case "login": 
         handleLogin(data.success); 
         break; 
      //when somebody wants to call us 
      case "offer": 
         handleOffer(data.offer, data.name); 
         break; 
      case "answer": 
         handleAnswer(data.answer); 
         break; 
      //when a remote peer sends an ice candidate to us 
      case "candidate": 
         handleCandidate(data.candidate); 
         break; 
      case "leave": 
         handleLeave(); 
         break; 
      default: 
         break; 
   }
};
  
conn.onerror = function (err) { 
   console.log("Got error", err); 
};
  
//alias for sending JSON encoded messages 
function send(message) { 
   //attach the other peer username to our messages 
   if (connectedUser) { 
      message.name = connectedUser; 
   } 
	
   conn.send(JSON.stringify(message)); 
};
  
//****** 
//UI selectors block 
//******
 
var loginPage = document.querySelector('#loginPage'); 
var usernameInput = document.querySelector('#usernameInput'); 
var loginBtn = document.querySelector('#loginBtn'); 

var callPage = document.querySelector('#callPage'); 
var callToUsernameInput = document.querySelector('#callToUsernameInput');
var callBtn = document.querySelector('#callBtn'); 

var hangUpBtn = document.querySelector('#hangUpBtn');
  
var localVideo = document.querySelector('#localVideo'); 
var remoteVideo = document.querySelector('#remoteVideo'); 

var yourConn; 
var stream;
  
callPage.style.display = "none";

// Login when the user clicks the button 
loginBtn.addEventListener("click", function (event) { 
   name = usernameInput.value;
	
   if (name.length > 0) { 
      send({ 
         type: "login", 
         name: name 
      }); 
   }
	
});
  
function handleLogin(success) { 
   if (success === false) { 
      alert("Ooops...try a different username"); 
   } else { 
      loginPage.style.display = "none"; 
      callPage.style.display = "block";
		
      //********************** 
      //Starting a peer connection 
      //********************** 
		
      //getting local video stream 
      navigator.webkitGetUserMedia({ video: true, audio: true }, function (myStream) { 
         stream = myStream; 
			
         //displaying local video stream on the page 
         localVideo.src = window.URL.createObjectURL(stream);
			
         //using Google public stun server 
         var configuration = { 
            "iceServers": [{ "url": "stun:stun2.1.google.com:19302" }]
         }; 
			
         yourConn = new webkitRTCPeerConnection(configuration); 
			
         // setup stream listening 
         yourConn.addStream(stream); 
			
         //when a remote user adds stream to the peer connection, we display it 
         yourConn.onaddstream = function (e) { 
            remoteVideo.src = window.URL.createObjectURL(e.stream); 
         };
			
         // Setup ice handling 
         yourConn.onicecandidate = function (event) { 
            if (event.candidate) { 
               send({ 
                  type: "candidate", 
                  candidate: event.candidate 
               }); 
            } 
         };  
			
      }, function (error) { 
         console.log(error); 
      }); 
		
   } 
};
  
//initiating a call 
callBtn.addEventListener("click", function () { 
   var callToUsername = callToUsernameInput.value;
	
   if (callToUsername.length > 0) { 
	
      connectedUser = callToUsername;
		
      // create an offer 
      yourConn.createOffer(function (offer) { 
         send({ 
            type: "offer", 
            offer: offer 
         }); 
			
         yourConn.setLocalDescription(offer); 
      }, function (error) { 
         alert("Error when creating an offer"); 
      });
		
   } 
});
  
//when somebody sends us an offer 
function handleOffer(offer, name) { 
   connectedUser = name; 
   yourConn.setRemoteDescription(new RTCSessionDescription(offer));
	
   //create an answer to an offer 
   yourConn.createAnswer(function (answer) { 
      yourConn.setLocalDescription(answer); 
		
      send({ 
         type: "answer", 
         answer: answer 
      }); 
		
   }, function (error) { 
      alert("Error when creating an answer"); 
   }); 
};
  
//when we got an answer from a remote user
function handleAnswer(answer) { 
   yourConn.setRemoteDescription(new RTCSessionDescription(answer)); 
};
  
//when we got an ice candidate from a remote user 
function handleCandidate(candidate) { 
   yourConn.addIceCandidate(new RTCIceCandidate(candidate)); 
};
   
//hang up 
hangUpBtn.addEventListener("click", function () { 

   send({ 
      type: "leave" 
   });  
	
   handleLeave(); 
});
  
function handleLeave() { 
   connectedUser = null; 
   remoteVideo.src = null; 
	
   yourConn.close(); 
   yourConn.onicecandidate = null; 
   yourConn.onaddstream = null; 
};

Резюме

Эта демонстрация предоставляет базовый набор функций, которые нужны каждому приложению WebRTC. Чтобы улучшить эту демонстрацию, вы можете добавить идентификацию пользователя с помощью таких платформ, как Facebook или Google, обрабатывать ввод пользователя для неверных данных. Кроме того, соединение WebRTC может прерваться из-за нескольких причин, таких как не поддержка технологии или неспособность пройти через брандмауэры. Работа над тем, чтобы сделать любое приложение WebRTC стабильным.