Added webRTC media connection

This commit is contained in:
Daniel Hervás Rodao 2021-06-27 22:14:04 +02:00
parent c0ba6d31d5
commit 9dad2c131b
2 changed files with 267 additions and 0 deletions

187
utils/stream/rtcstream.js Normal file
View File

@ -0,0 +1,187 @@
'use strict';
let stream;
let localStream;
let localPeer;
let remotePeer;
const constraints = {
video: {
mediaSource: "screen", // whole screen sharing
//mediaSource: "window", // choose a window to share
//mediaSource: "application", // choose a window to share
width: {max: '1920'},
height: {max: '1080'},
frameRate: {max: '10'}
}
};
const offerOptions = {
OfferToReceiveAudio: 1,
OfferToReceiveVideo: 1
};
var configuration = {
"iceServers": [{ "urls": "stun:stun.1.google.com:19302" }]
};
let iceCandidates = [];
function checkUsers() {
streamws.send(
JSON.stringify({
type: "check-users",
})
);
}
// Empezar el streaming local:
// 1. Desactivar el botón de start, localVideo.play(),
// obtener el media stream, establecer localVideo.srcObject = stream y
// dar valor a la variable localStream con el stream que hemos obtenido.
// 2. Crear la instancia de la RTCPeerConnection
// 3. Crear el handler del evento icecandidate
// 4. Añadir los media tracks del localStream para que sean enviadas
// al remote peer
// 5. Crear la oferta de candidato en el extremo local
// 6. Crear la descripción local de localPeer
async function startLocalStream(){
console.log('[NOVNC] empezando stream local');
// Obtener el stream del usuario
if(!canvas){
console.log('[NOVNC] Error: no CANVAS');
return
}
stream = canvas.captureStream();
// Mostrar el video
localVideo.srcObject = stream;
// Establecer cual es el localStream
localStream = stream;
// Crear instancia de RTCPeerConnection
localPeer = new RTCPeerConnection(configuration);
// Send candidate to the remote peer
localPeer.addEventListener('icecandidate', event => onIceCandidate(localPeer, event));
// Añadir los media tracks que genera el localStream a
// las tracks de localPeer para enviarlas al remote peer
localStream.getTracks().forEach(track => localPeer.addTrack(track, localStream));
console.log('[NOVNC] Adding tracks');
// Crear oferta
localPeer.createOffer(offerOptions);
// Establecer la descripcion de localPeer
localPeer.addEventListener('negotiationneeded', addLocalDescription(localPeer));
}
// Cuando recibo un socket del tipo offer:
// 1. Creo la instancia de la conexión RTC del extemo remoto
// 2. Creo el hadler para el evento icecandidate
// 3. Handler para recibir los mediatracks
// 4. Notifico si el estado del remotePeer cambia
// 5. Establezco la descripcion remota del extremo remoto
// 6. Crear respuesta y establecer la descripcion local del extremo remoto
// 7. Enviar un websocket con la respuesta al otro peer
async function startRemoteStream(offer){
// Creo la instancia de la conexión remota
remotePeer = new RTCPeerConnection(configuration);
console.log('[NOVNC] RTC Remote Peer conection created');
// Handler para el evento icecandidate
// Send candidate to the remote peer
remotePeer.addEventListener('icecandidate', event => onIceCandidate(remotePeer, event));
// Recibir los media tracks del extremo local
remotePeer.ontrack = gotRemoteStream;
// Notificar si el estado remoto cambia
remotePeer.oniceconnectionstatechange = () => console.log('Remote ice state ' + remotePeer.iceConnectionState);
// Set remote description
try {
remotePeer.setRemoteDescription(offer);
console.log('[NOVNC] Remote description set');
} catch (error) {
console.log(`[NOVNC] Set remote description error: ${error}`);
}
try {
// Create answer
const answer = await remotePeer.createAnswer();
// Set local description of remote peer
remotePeer.setLocalDescription(answer);
// Signal localStream peer with the answer
signalRemotePeer(JSON.stringify({
'type':'answer',
'answer':answer
}));
}catch(error){
console.log(`[NOVNC] Failed to create local session description ${error}`);
}
}
function addIceCandidate(candidate) {
//var candidate = new RTCIceCandidate(cand)
if (localPeer === undefined) {
remotePeer.addIceCandidate(candidate);
} else {
localPeer.addIceCandidate(candidate);
}
console.log('[NOVNC] Candidate Added');
}
async function setAnswerDescription(answer){
try {
localPeer.setRemoteDescription(answer);
console.log("[NOVNC] Local Peer remote description set");
}catch(error){
console.log(`[NOVNC] Failed setting local peer remote description ${error}`);
}
}
// Añadir los candidatos a la lista de candidatos
function onIceCandidate(peer, event){
if(event.candidate != null && event.candidate != undefined){
console.log(`[NOVNC] onicecandidate event on ${peer}`);
// Send the candidate to the other peer via WebSockets
signalRemotePeer(JSON.stringify({
'type':'candidate',
'candidate':event.candidate
}));
}
}
async function addLocalDescription(peer) {
try {
const offer = await peer.createOffer(offerOptions);
peer.setLocalDescription(offer);
console.log(`[NOVNC] ${peer} local description set`);
signalRemotePeer(JSON.stringify({
'type':'offer',
'offer':offer
}));
} catch(err) {
console.log(`[NOVNC] ${peer} error setting local description`);
}
}
function signalRemotePeer(data){
streamws.send(data);
console.log('[NOVNC] Signaling remote peer...');
}
function gotRemoteStream(e){
console.log('[NOVNC] Got remote video: ', e.streams[0]);
if (remoteVideo.srcObject !== e.streams[0]) {
//rightVideo.play();
remoteVideo.srcObject = e.streams[0];
console.log('[NOVNC] pc2 received remote stream');
}
}

80
utils/stream/ws_chat.js Normal file
View File

@ -0,0 +1,80 @@
'use strict';
// Create websocket for communication
const websocket = new WebSocket(
'ws://' +
window.location.host +
'/ws/chat/' +
room_name +
'/'
);
console.log('Websocket created for room: ', room_name);
let token = new Date().getTime() + Math.random();
console.log('token: ',token);
websocket.onmessage = function(event){
let message_data = JSON.parse(event.data);
console.log('WebSocket received: ', message_data);
// If the content type from the websocket is chat_message,
// the text field is appended to the chat box
if(message_data['type'] == 'chat_message'){
if(Number(token) !== Number(message_data['token'])){
console.log('Escribir mensaje');
add_message('receive', message_data['message']);
}
}else if(message_data['type'] == 'candidate'){
console.log('Candidate received');
addIceCandidate(message_data['candidate']);
}else if(message_data['type'] == 'offer'){
console.log('Offer received');
startRemoteStream(message_data['offer']);
}else if(message_data['type'] == 'answer'){
console.log('Answer received');
setAnswerDescription(message_data['answer']);
}else if(message_data['type'] == 'denied'){
console.log('Denied connection');
window.location.pathname = '/';
}else if(message_data['type'] == 'checkusers'){
if(message_data['users']){
startLocalStream()
}else{
console.log('No peer connected')
}
}
};
function add_message(direction, message){
let chat_log = document.querySelector('#chat-log');
if(direction === 'send'){
chat_log.innerHTML += ('<p class="send"> [You] ' + message + '</p>');
}else if(direction === 'receive'){
chat_log.innerHTML += ('<p class="receive"> [Sender] ' + message + '</p>');
}
}
// Focus al input text
document.querySelector('#chat-message-input').focus();
// On Enter pressed, the WebSocket is sent
document.querySelector('#chat-message-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#chat-message-submit').click();
}
};
// Al hacer click en el botón de enviar el websocket se envía
document.querySelector('#chat-message-submit').onclick = function(e) {
const messageInputDom = document.querySelector('#chat-message-input');
const message = messageInputDom.value;
websocket.send(JSON.stringify({
'type':'chat_message',
'token':token,
'message': message,
}));
console.log('WebSocket sent!');
add_message('send', message);
messageInputDom.value = '';
};