Send message to iframe inside of a promise - javascript

I have this promise? How can I postMessage to an iframe from then. Currently i have function with timer that sends info on page load but i want to get more info.
const socket = io('/')
const videoGrid = document.getElementById('video-grid')
const myPeer = new Peer(undefined, {
path: '/peerjs',
host: '/',
port: '3000'
})
const peers = {}
let myVideoStream;
const myVideo = document.createElement('video')
myVideo.muted = true;
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function brodcastStatus(postMsg) {
for (let i = 0; i < 10; i++) {
parent.postMessage(postMsg, "*");
console.log(postMsg)
await sleep(1500)
}
}
if (KIND === 'server'){
Promise.resolve(navigator.mediaDevices.getUserMedia({
video: {
width: 1920,
height: 1080,
aspectRatio: { ideal: 1.7777777778 },
frameRate: { max: 24, }
},
audio: true
})).then(stream => {
brodcastStatus("server | camera | mic")
myVideoStream = stream;
myPeer.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)
})
}).catch(() => {
Promise.resolve(navigator.mediaDevices.getUserMedia({
video: {
width: 1920,
height: 1080,
aspectRatio: { ideal: 1.7777777778 },
frameRate: { max: 24, }
},
audio: false
})).then(stream => {
brodcastStatus("server | camera | no mic")
myVideoStream = stream;
myPeer.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)
})
}).catch(() => {
console.log("nocamera or microphone")
})
})
}else if (KIND === 'client'){
Promise.resolve(navigator.mediaDevices.getUserMedia({
video: false,
audio: true
})).then(stream => {
brodcastStatus("client | no camera | mic")
myVideoStream = stream;
myPeer.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)
})
}).catch(() => {
console.log("Client")
newStream = new MediaStream();
stream = newStream;
myVideoStream = stream;
myPeer.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)
})
})
}
socket.on('user-disconnected', userId => {
if (peers[userId]) peers[userId].close()
})
myPeer.on('open', id => {
socket.emit('join-room', ROOM_ID, id)
})
function connectToNewUser(userId, stream) {
const call = myPeer.call(userId, stream)
const video = document.createElement('video')
call.on('stream', userVideoStream => {
addVideoStream(video, userVideoStream)
})
call.on('close', () => {
video.remove()
})
peers[userId] = call
}
function addVideoStream(video, stream) {
video.srcObject = stream
video.setAttribute("style", "object-fit:cover; background: transparent url(/images/New_DACL_Logo.png) no-repeat center center; background-size: auto; overflow: hidden;")
video.addEventListener('loadedmetadata', () => {
})
videoGrid.append(video)
}
More context
this app send audio/video to user via webrtc. I using this webpage as an iframe in other application (flask) and i want to get some data about current connected user to lock/unlock other options

Related

WebRtc works on Firefox but not on Chrome after changing signaling

I basicly Implemented a simple webrtc application where a client streams a video and then another client can connect and access the remote stream from each other.
The first implementation I did was with AgoraRTM signaling and it worked well in all browsers. After that I wanted to try to move to websockets as the signaling part.
When I finished moving to websockets, I noticed that it kept working at Firefox, but at Chrome and Edge (probably chromium browsers) the remoteStream doesn't show up (it shows up the first and second time, but stops working if I disconnect and connect a new client)
Here is my code:
main.js (frontend logic, webrtc)
let token = null;
let uid = String(Math.floor(Math.random() * 10000));
let queryString = window.location.search;
const urlSearch = new URLSearchParams(queryString);
const room = urlSearch.get("room");
if (!room) {
window.location = "lobby.html";
}
let client;
let channel;
let socket;
const constraints = {
video: {
width: { min: 640, ideal: 1920, max: 1920 },
height: { min: 480, ideal: 1080, max: 1920 },
aspectRatio: 1.777777778,
},
audio: false,
};
const servers = {
iceServers: [
{
urls: [
"stun:stun.l.google.com:19302",
"stun:stun1.l.google.com:19302",
"stun:stun2.l.google.com:19302",
"stun:stun3.l.google.com:19302",
"stun:stun4.l.google.com:19302",
],
},
],
};
const localVideoRef = document.getElementById("localVideo");
const remoteVideoRef = document.getElementById("remoteVideo");
let localStream;
let remoteStream;
let peerConnection;
const configureSignaling = async () => {
socket = await io.connect("http://localhost:4000");
socket.emit("join", { room, uid });
socket.on("MemberJoined", handleMemberJoined);
socket.on("MessageFromPeer", handleMessageFromPeer);
socket.on("MemberLeft", handleMemberLeft)
};
const handleMemberLeft = async () => {
remoteVideoRef.style.display = "none";
};
const handleMessageFromPeer = (m, uid) => {
const message = JSON.parse(m.text);
if(message.type !== "candidate") {
console.log('handleMessageFromPeer: ', message, uid)
}
if (message.type === "offer") {
createAnswer(uid, message.offer);
}
if (message.type === "answer") {
addAnswer(message.answer);
}
if (message.type === "candidate") {
if (peerConnection && peerConnection.currentRemoteDescription) {
peerConnection.addIceCandidate(message.candidate);
}
}
};
const createLocalStream = async () => {
localStream = await navigator.mediaDevices.getUserMedia(constraints);
localVideoRef.srcObject = localStream;
localVideoRef.play()
remoteVideoRef.play()
};
const init = async () => {
await configureSignaling();
await createLocalStream();
};
const handleMemberJoined = async (uid) => {
createOffer(uid);
};
let createOffer = async (uid) => {
await createPeerConnection(uid);
let offer = await peerConnection.createOffer();
console.log({ offer })
await peerConnection.setLocalDescription(offer);
console.log('localStream: ', offer)
socket.emit(
"sendMessageToPeer",
{ text: JSON.stringify({ type: "offer", offer: offer }) },
uid
);
};
let createPeerConnection = async (uid) => {
peerConnection = new RTCPeerConnection(servers);
remoteStream = new MediaStream();
remoteVideoRef.srcObject = remoteStream;
remoteVideoRef.style.display = "block";
remoteVideoRef.classList.add("remoteFrame");
if (!localStream) {
await createLocalStream();
}
localStream.getTracks().forEach((track) => {
peerConnection.addTrack(track, localStream);
});
peerConnection.ontrack = (event) => {
event.streams[0].getTracks().forEach((track) => {
remoteStream.addTrack(track);
});
};
peerConnection.onicecandidate = (event) => {
if (event.candidate) {
socket.emit(
"sendMessageToPeer",
{
text: JSON.stringify({
type: "candidate",
candidate: event.candidate,
}),
},
uid
);
}
};
};
let createAnswer = async (uid, offer) => {
await createPeerConnection(uid);
await peerConnection.setRemoteDescription(offer);
console.log('remoteStream: ', offer)
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);
console.log('localStream: ', answer)
socket.emit(
"sendMessageToPeer",
{ text: JSON.stringify({ type: "answer", answer: answer }) },
uid
);
};
let addAnswer = async (answer) => {
if (!peerConnection.currentRemoteDescription) {
peerConnection.setRemoteDescription(answer);
}
console.log(peerConnection)
};
let onLogout = async () => {
peerConnection.close()
remoteVideoRef.classList.remove("remoteFrame");
await socket.emit('onLeaveRoom', room)
};
let onToggleCamera = async () => {
const videoTrack = localStream
.getTracks()
.find((track) => track.kind === "video");
if (videoTrack.enabled) {
videoTrack.enabled = false;
document.getElementById("camera-btn").style.backgroundColor =
"rgb(255, 80, 80)";
} else {
videoTrack.enabled = true;
document.getElementById("camera-btn").style.backgroundColor =
"rgb(179, 102, 249, .9)";
}
};
let onToggleMic = async () => {
const audioTrack = localStream
.getTracks()
.find((track) => track.kind === "audio");
if (audioTrack.enabled) {
audioTrack.enabled = false;
document.getElementById("mic-btn").style.backgroundColor =
"rgb(255, 80, 80)";
} else {
audioTrack.enabled = true;
document.getElementById("mic-btn").style.backgroundColor =
"rgb(179, 102, 249, .9)";
}
};
window.addEventListener("beforeunload", onLogout);
init();
index.js (server logic, websockets)
const express = require("express");
const app = express();
const PORT = 4000;
const http = require("http").Server(app);
const cors = require("cors");
const users = []
app.use(cors());
const socketIO = require("socket.io")(http, {
cors: {
origin: "http://127.0.0.1:5501",
},
});
//Add this before the app.get() block
socketIO.on("connection", (socket) => {
socket.on('join', async ({room, uid}) => {
users.push(uid)
await socket.join(room);
socket.broadcast.to(room).emit('MemberJoined', uid)
})
socket.on("onLeaveRoom", async (room) => {
socket.broadcast.to(room).emit('MemberLeft')
})
socket.on("disconnect", async (room) => {
socket.broadcast.to(room).emit('MemberLeft')
})
socket.on('sendMessageToPeer', (data, uid) => {
socket.broadcast.emit('MessageFromPeer', data, uid )
});
});
app.get("/api", (req, res) => {
res.json({
message: "Hello world",
});
});
http.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
});
I tried a couple of things like:
Checking if the offer and the answer was sended correctly, just 1 time and with the correct SDP
Checked if there was a problem disconnecting from a socket that leads to have more clients in a room
Tried also to add localVideoRef.play() to check if there is an issue with the autoplay for chrome, since there was a similar thread at stackoverflow (Ended up not working)

How to switch between front camera and rear camera in javascript?

let constraints;
function handleVideo(){
const constraints = {
video: {
facingMode: {
exact: 'user'
}
}
};
var video;
navigator.mediaDevices.getUserMedia(constraints).
then((stream) => {
video = document.createElement("video")
video.srcObject = stream
video.play()
video.onloadeddata = () => {
ctx.height = video.videoHeight
}
})
}
I know by changing exact to environment can switch between front and back camera. But I don't know how to do this onclick.
Something like this :
function handleVideo(cameraFacing) {
const constraints = {
video: {
facingMode: {
exact: cameraFacing
}
}
}
return constraints
};
function turnVideo(constraints) {
let video;
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
video = document.createElement("video")
video.srcObject = stream
video.play()
video.onloadeddata = () => {
ctx.height = video.videoHeight
}
})
}
document.querySelector(".frontCamera").addEventListener("click", () => {
turnVideo(handleVideo("user"));
})
document.querySelector(".backCamera").addEventListener("click", () => {
turnVideo(handleVideo("enviroment"));
})
<div class="frontCamera">front</div>
<div class="backCamera">back</div>

WebRTC Video Conference Change the quality of video NodeJS

I am trying to create a video conference app using the tutorial https://youtu.be/DvlyzDZDEq4 . I want to add one feature to change the quality of video( not the resolution of the video ) user can see like we have in YouTube videos auto, high picture quality etc. I am very new to WebRTC and Peer library so any help is appreciated. Thank you.
script.js
const socket = io('/')
const videoGrid = document.getElementById('video-grid')
const myPeer = new Peer(undefined, {
host: '/',
port: '3001'
})
const myVideo = document.createElement('video')
myVideo.muted = true
const peers = {}
navigator.mediaDevices.getUserMedia({
video: true,
audio: true
}).then(stream => {
addVideoStream(myVideo, stream)
myPeer.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)
})
})
socket.on('user-disconnected', userId => {
if (peers[userId]) peers[userId].close()
})
myPeer.on('open', id => {
socket.emit('join-room', ROOM_ID, id)
})
function connectToNewUser(userId, stream) {
const call = myPeer.call(userId, stream)
const video = document.createElement('video')
call.on('stream', userVideoStream => {
addVideoStream(video, userVideoStream)
})
call.on('close', () => {
video.remove()
})
peers[userId] = call
}
function addVideoStream(video, stream) {
video.srcObject = stream
video.addEventListener('loadedmetadata', () => {
video.play()
})
videoGrid.append(video)
}
room.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script>
const ROOM_ID = "<%= roomId %>"
</script>
<script defer src="https://unpkg.com/peerjs#1.2.0/dist/peerjs.min.js"></script>
<script src="/socket.io/socket.io.js" defer></script>
<script src="script.js" defer></script>
</head>
<body>
<div id="video-grid"></div>
</body>
</html>
server.js
const express = require('express')
const app = express()
const server = require('http').Server(app)
const io = require('socket.io')(server)
const { v4: uuidV4 } = require('uuid')
app.set('view engine', 'ejs')
app.use(express.static('public'))
app.get('/', (req, res) => {
res.redirect(`/${uuidV4()}`)
})
app.get('/:room', (req, res) => {
res.render('room', { roomId: req.params.room })
})
io.on('connection', socket => {
socket.on('join-room', (roomId, userId) => {
socket.join(roomId)
socket.to(roomId).broadcast.emit('user-connected', userId)
socket.on('disconnect', () => {
socket.to(roomId).broadcast.emit('user-disconnected', userId)
})
})
})
server.listen(3000)
Updated Script.js
const socket = io('/zoom')
const videoGrid = document.getElementById('video-grid')
const myPeer = new Peer(undefined, {
host: '/',
port: '3002'
})
let pc;
const myVideo = document.createElement('video')
myVideo.muted = true
const peers = {}
let myVideoStream;
navigator.mediaDevices.getUserMedia({
video: true,
audio: true
}).then(stream => {
myVideoStream = stream;
addVideoStream(myVideo, stream,user)
myPeer.on('call', call => {
call.answer(stream)
const video = document.createElement('video')
call.on('stream', userVideoStream => {
addVideoStream(video, userVideoStream,user)
})
})
socket.on("user-connected", (userId, username) =>
{ console.log("checking "+ username);
setTimeout(function ()
{ connectToNewUser(userId, stream);
console.log("zoooom "+ username);
}, 1000);
});
let text = $("input");
// when press enter send message
$('html').keydown(function (e) {
if (e.which == 13 && text.val().length !== 0) {
socket.emit('message', text.val());
text.val('')
}
});
socket.on("createMessage", (message, username) => {
//$("ul").append(`<li class="message"><b>${username}</b><br/>${message}</li>`);
scrollToBottom()
})
})
socket.on('user-disconnected', (userId, username) => {
$("ul").append(`<span class="messageHeader"><small>${username} Left Meeting</small></span>`);
if (peers[userId]) peers[userId].close()
})
const offerOptions = {
offerToReceiveAudio: 0,
offerToReceiveVideo: 1
};
myPeer.on('open', id => {
const servers = null;
pc1 = new RTCPeerConnection(servers);
pc1.createOffer({
offerToReceiveAudio: 0,
offerToReceiveVideo: 1
})
.then((desc)=>{const videobitrate = 20000;
return pc1.setLocalDescription(desc);
/* let offer = pc1.localDescription;
console.log("offer "+pc1.localDescription);
// Set bandwidth for video
offer.sdp = offer.sdp.replace(/(m=video.*\r\n)/g, `$1b=AS:125\r\n`);
pc1.setLocalDescription(offer);*/}).then(()=>{
let offer = pc1.localDescription;
console.log("offer "+pc1.localDescription);
// Set bandwidth for video
offer.sdp = offer.sdp.replace(/(m=video.*\r\n)/g, `$1b=AS:20000\r\n`);
return pc1.setLocalDescription(offer);
}).then(()=>{console.log(pc1.localDescription.sdp)})
.catch((err)=>{ console.log('Failed to set session description: ' + err);});
console.log("user mypeer"+user);
socket.emit('join-room', ROOM_ID,id,user);
})
function connectToNewUser(userId, stream) {
const call = myPeer.call(userId, stream)
const servers = null;
pc2 = new RTCPeerConnection(servers);
pc2.createOffer({
offerToReceiveAudio: 0,
offerToReceiveVideo: 1
})
.then((desc)=>{const videobitrate = 20000;
return pc2.setLocalDescription(desc);
/* let offer = pc1.localDescription;
console.log("offer "+pc1.localDescription);
// Set bandwidth for video
offer.sdp = offer.sdp.replace(/(m=video.*\r\n)/g, `$1b=AS:125\r\n`);
pc1.setLocalDescription(offer);*/}).then(()=>{
let offer = pc2.localDescription;
console.log("offer "+pc2.localDescription);
// Set bandwidth for video
offer.sdp = offer.sdp.replace(/(m=video.*\r\n)/g, `$1b=AS:20000\r\n`);
return pc2.setLocalDescription(offer);
}).then(()=>{console.log(pc2.localDescription.sdp)})
.catch((err)=>{ console.log('Failed to set session description: ' + err);});
const video = document.createElement('video')
call.on('stream', userVideoStream => {
addVideoStream(video, userVideoStream,user)
})
call.on('close', () => {
video.remove()
})
peers[userId] = call
}
function addVideoStream(video, stream,username) {
video.srcObject = stream
console.log("adding video")
video.addEventListener('loadedmetadata', () => {
video.play()
})
videoGrid.append(video)
video.insertAdjacentHTML('beforebegin',`<b style="color:white">${username}</b>`);
}
const scrollToBottom = () => {
var d = $('.main__chat_window');
d.scrollTop(d.prop("scrollHeight"));
}
const muteUnmute = () => {
const enabled = myVideoStream.getAudioTracks()[0].enabled;
if (enabled) {
myVideoStream.getAudioTracks()[0].enabled = false;
setUnmuteButton();
} else {
setMuteButton();
myVideoStream.getAudioTracks()[0].enabled = true;
}
}
const playStop = () => {
console.log('object')
let enabled = myVideoStream.getVideoTracks()[0].enabled;
if (enabled) {
myVideoStream.getVideoTracks()[0].enabled = false;
setPlayVideo()
} else {
setStopVideo()
myVideoStream.getVideoTracks()[0].enabled = true;
}
}
const setMuteButton = () => {
const html = `
<i class="fas fa-microphone"></i>
<span>Mute</span>
`
document.querySelector('.main__mute_button').innerHTML = html;
}
const setUnmuteButton = () => {
const html = `
<i class="unmute fas fa-microphone-slash"></i>
<span>Unmute</span>
`
document.querySelector('.main__mute_button').innerHTML = html;
}
const setStopVideo = () => {
const html = `
<i class="fas fa-video"></i>
<span>Stop Video</span>
`
document.querySelector('.main__video_button').innerHTML = html;
}
const setPlayVideo = () => {
const html = `
<i class="stop fas fa-video-slash"></i>
<span>Play Video</span>
`
document.querySelector('.main__video_button').innerHTML = html;
}

PeerJs Issue On locahost

I am trying to implement the zoom clone with WebRTC using peerjs, the problem is myPeer.on("call", (call) => { its never calling, this same code is executing on the locahost for the others who made the tutorial on zoom clone, I am not sure where is the problem with my code,
Its working on heroku though its not working on localhost, so where is the problem with my localhost setup, why i am not getting the other users who joined the room on localhost, I am not understanding.
script.js
const socket = io("/");
const videoGrid = document.getElementById("video-grid");
const myPeer = new Peer(undefined, {
path: "/peerjs",
host: "/",
port: "3030",
});
let myVideoStream;
const myVideo = document.createElement("video");
myVideo.muted = true;
const peers = {};
navigator.mediaDevices
.getUserMedia({
video: true,
audio: true,
})
.then((stream) => {
myVideoStream = stream;
addVideoStream(myVideo, stream);
// Never Called this myPeer.on call
myPeer.on("call", (call) => {
call.answer(stream);
const video = document.createElement("video");
call.on("stream", (userVideoStream) => {
addVideoStream(video, userVideoStream);
});
});
socket.on("user-connected", (userId) => {
console.log("User Connected", userId);
connectToNewUser(userId, stream);
});
// input value
let text = $("input");
// when press enter send message
$("html").keydown(function (e) {
if (e.which == 13 && text.val().length !== 0) {
socket.emit("message", text.val());
text.val("");
}
});
socket.on("createMessage", (message) => {
$("ul").append(`<li class="message"><b>user</b><br/>${message}</li>`);
scrollToBottom();
});
});
socket.on("user-disconnected", (userId) => {
if (peers[userId]) peers[userId].close();
});
myPeer.on("open", (id) => {
socket.emit("join-room", ROOM_ID, id);
});
function connectToNewUser(userId, stream) {
const call = myPeer.call(userId, stream);
const video = document.createElement("video");
call.on("stream", (userVideoStream) => {
addVideoStream(video, userVideoStream);
});
call.on("close", () => {
video.remove();
});
peers[userId] = call;
}
function addVideoStream(video, stream) {
video.srcObject = stream;
video.addEventListener("loadedmetadata", () => {
video.play();
});
videoGrid.append(video);
}
const scrollToBottom = () => {
var d = $(".main__chat_window");
d.scrollTop(d.prop("scrollHeight"));
};
const muteUnmute = () => {
const enabled = myVideoStream.getAudioTracks()[0].enabled;
if (enabled) {
myVideoStream.getAudioTracks()[0].enabled = false;
setUnmuteButton();
} else {
setMuteButton();
myVideoStream.getAudioTracks()[0].enabled = true;
}
};
const playStop = () => {
console.log("object");
let enabled = myVideoStream.getVideoTracks()[0].enabled;
if (enabled) {
myVideoStream.getVideoTracks()[0].enabled = false;
setPlayVideo();
} else {
setStopVideo();
myVideoStream.getVideoTracks()[0].enabled = true;
}
};
const setMuteButton = () => {
const html = `
<i class="fas fa-microphone"></i>
<span>Mute</span>
`;
document.querySelector(".main__mute_button").innerHTML = html;
};
const setUnmuteButton = () => {
const html = `
<i class="unmute fas fa-microphone-slash"></i>
<span>Unmute</span>
`;
document.querySelector(".main__mute_button").innerHTML = html;
};
const setStopVideo = () => {
const html = `
<i class="fas fa-video"></i>
<span>Stop Video</span>
`;
document.querySelector(".main__video_button").innerHTML = html;
};
const setPlayVideo = () => {
const html = `
<i class="stop fas fa-video-slash"></i>
<span>Play Video</span>
`;
document.querySelector(".main__video_button").innerHTML = html;
};
server.js
const express = require("express");
const app = express();
// const cors = require('cors')
// app.use(cors())
const server = require("http").Server(app);
const io = require("socket.io")(server);
const { ExpressPeerServer } = require("peer");
const peerServer = ExpressPeerServer(server, {
debug: true,
});
const { v4: uuidV4 } = require("uuid");
app.use("/peerjs", peerServer);
app.set("view engine", "ejs");
app.use(express.static("public"));
app.get("/", (req, res) => {
res.redirect(`/${uuidV4()}`);
});
app.get("/:room", (req, res) => {
res.render("room", { roomId: req.params.room });
});
io.on("connection", (socket) => {
socket.on("join-room", (roomId, userId) => {
socket.join(roomId);
socket.to(roomId).broadcast.emit("user-connected", userId);
// messages
socket.on("message", (message) => {
//send message to the same room
io.to(roomId).emit("createMessage", message);
});
socket.on("disconnect", () => {
socket.to(roomId).broadcast.emit("user-disconnected", userId);
});
});
});
server.listen(process.env.PORT || 3030);
the function connectToNewUser get executed before the myPeer.on('call')
try modifying the function as
socket.on("user-connected", (userId) => {
console.log("User Connected", userId);
//connectToNewUser(userId, stream);
setTimeout(connectToNewUser,1000,userId,stream)
});
I had the same issue and it seemed to be a race condition with socket.emit("join-room", ROOM_ID, id);.
The server will emit socket.to(roomId).broadcast.emit("user-connected", userId); which will trigger the function that calls the peer in connectToNewUser before the user has finished the navigator promise.
I solved my issue by making sure the navigator promise has finished before firing socket.emit("join-room", ROOM_ID, id);.

Webrtc video broadcasting Viewer only works sometimes

I´m using Gabriel Tanners video broadcasting Tutorial on localhost it works great! Over Internet connection most of the times the viewer simply doesn't show anything. I spent hours testing and changing the lifecycle. Nothing works.
Here´s the Broadcaster code:
const peerConnections = {};
const config = {
iceServers: [
{
urls: ["stun:stun.l.google.com:19302"]
}
]
};
const socket = io.connect(window.location.origin);
socket.on("answer", (id, description) => {
peerConnections[id].setRemoteDescription(description);
});
socket.on("watcher", id => {
const peerConnection = new RTCPeerConnection(config);
peerConnections[id] = peerConnection;
let stream = videoElement.srcObject;
stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
peerConnection.onicecandidate = event => {
if (event.candidate) {
socket.emit("candidate", id, event.candidate);
}
};
peerConnection
.createOffer()
.then(sdp => peerConnection.setLocalDescription(sdp))
.then(() => {
socket.emit("offer", id, peerConnection.localDescription);
});
});
socket.on("candidate", (id, candidate) => {
peerConnections[id].addIceCandidate(new RTCIceCandidate(candidate));
});
socket.on("disconnectPeer", id => {
peerConnections[id].close();
delete peerConnections[id];
});
window.onunload = window.onbeforeunload = () => {
socket.close();
};
// Get camera and microphone
const videoElement = document.querySelector("video");
const audioSelect = document.querySelector("select#audioSource");
const videoSelect = document.querySelector("select#videoSource");
audioSelect.onchange = getStream;
videoSelect.onchange = getStream;
getStream()
.then(getDevices)
.then(gotDevices);
function getDevices() {
return navigator.mediaDevices.enumerateDevices();
}
function gotDevices(deviceInfos) {
window.deviceInfos = deviceInfos;
for (const deviceInfo of deviceInfos) {
const option = document.createElement("option");
option.value = deviceInfo.deviceId;
if (deviceInfo.kind === "audioinput") {
option.text = deviceInfo.label || `Microphone ${audioSelect.length + 1}`;
audioSelect.appendChild(option);
} else if (deviceInfo.kind === "videoinput") {
option.text = deviceInfo.label || `Camera ${videoSelect.length + 1}`;
videoSelect.appendChild(option);
}
}
}
function getStream() {
if (window.stream) {
window.stream.getTracks().forEach(track => {
track.stop();
});
}
const audioSource = audioSelect.value;
const videoSource = videoSelect.value;
const constraints = {
audio: { deviceId: audioSource ? { exact: audioSource } : undefined },
video: { deviceId: videoSource ? { exact: videoSource } : undefined }
};
return navigator.mediaDevices
.getUserMedia(constraints)
.then(gotStream)
.catch(handleError);
}
function gotStream(stream) {
window.stream = stream;
audioSelect.selectedIndex = [...audioSelect.options].findIndex(
option => option.text === stream.getAudioTracks()[0].label
);
videoSelect.selectedIndex = [...videoSelect.options].findIndex(
option => option.text === stream.getVideoTracks()[0].label
);
videoElement.srcObject = stream;
socket.emit("broadcaster");
}
function handleError(error) {
console.error("Error: ", error);
}
The viewer:
let peerConnection;
const config = {
iceServers: [
{
urls: ["stun:stun.l.google.com:19302"]
}
]
};
const socket = io.connect(window.location.origin);
const video = document.querySelector("video");
socket.on("offer", (id, description) => {
peerConnection = new RTCPeerConnection(config);
peerConnection
.setRemoteDescription(description)
.then(() => peerConnection.createAnswer())
.then(sdp => peerConnection.setLocalDescription(sdp))
.then(() => {
socket.emit("answer", id, peerConnection.localDescription);
});
peerConnection.ontrack = event => {
video.srcObject = event.streams[0];
};
peerConnection.onicecandidate = event => {
if (event.candidate) {
socket.emit("candidate", id, event.candidate);
}
};
});
socket.on("candidate", (id, candidate) => {
peerConnection
.addIceCandidate(new RTCIceCandidate(candidate))
.catch(e => console.error(e));
});
socket.on("connect", () => {
socket.emit("watcher");
});
socket.on("broadcaster", () => {
socket.emit("watcher");
});
socket.on("disconnectPeer", () => {
peerConnection.close();
});
window.onunload = window.onbeforeunload = () => {
socket.close();
};
I´m very thankful for your help
Since the two devices are not in the same network, you will need a TURN server for the establishment of the connection. A TURN server is used to relay as a relay if the peer-to-peer connection fails, which seems to be happening in your case.
Since there are no public TURN servers out there, you will probably need to create your own. For that, I can recommend the following options:
Coturn - Has a lot of possible configuration options but is thereby harder to set up.
Pion TURN - Easier to set up but doesn't feature as many possibilities
If you want to learn more about the internal of WebRTC and how they work together, checkout out webrtcforthecurious.

Categories

Resources