Webrtc how to set the video remote after receiver back an asnwer - javascript

hello to all I am new in this I have all almost done,but just on my initiator for say something I don't know the way for receiver the remote video stream after receiver the answer, can some one help me please ?
this is my client
$(document).ready(() => {
const configuration = {
iceServers: [{ url: 'stun:stun2.1.google.com:19302' }]
}
var peerConection = null;
// var btnCall = $('body #call');
var list = $('#mylist');
var TitlePrint = $('#titleUser');
var localVideo = document.getElementById('local');
var remoteVideo = document.getElementById('remote');
var userid = null;
var socket = io();
socket.on('connect', () => {
userid = socket.id
TitlePrint.text(userid);
});
socket.on('users', data => {
var users = [];
list.empty();
for (let index = 0; index < data.user.length; index++) {
if (data.user[index] != userid) {
users.push(`<button id="call" class="list-group-item list-group-item-action" data-ids="${data.user[index]}">${data.user[index]}</button>`);
}
}
if (users.length != 0) {
list.html(users);
} else {
list.html(`<div class="list-group-item"> Any users connected! </div>`);
}
});
$('body').on('click', '#call', function () {
let toId = $(this).attr('data-ids');
socket.emit('initiator', { initiatorid: userid, receiverid: toId });
});
socket.on('initiator', data => {
peerConection = createRTC(socket);
if (data.initiatorid === userid) {
console.log('this is the initiator');
initiateSignaling(socket, peerConection, data.receiverid, data.initiatorid);
} else {
console.log('this is the receiver');
prepareToReceiveOffer(socket, peerConection, data.initiatorid, data.receiverid);
}
});
// =============== HELPERS =====================//
function createRTC(socket) {
console.log('createRTC')
var peerConection = new RTCPeerConnection(configuration);
peerConection.onicecandidate = (e) => {
if (e.candidate) {
console.log('emit candidate')
socket.emit('send-candidate', e.candidate);
}
}
socket.on('receiver-candidate', (candidate) => {
peerConection.addIceCandidate(candidate);
});
return peerConection;
}
function initiateSignaling(socket, peerConection, targetID, from) {
navigator.mediaDevices.getUserMedia({ video: true, audio: false }).then((stream) => {
stream.getTracks().forEach(function (track) {
peerConection.addTrack(track, stream);
});
localVideo.srcObject = stream;
peerConection.createOffer().then(function (offer) {
return peerConection.setLocalDescription(offer);
})
.then(function () {
socket.emit('send-offer', {
from: from,
target: targetID,
type: "send-offer",
sdp: peerConection.localDescription
});
})
.catch(function (reason) {
console.log('error on create offer', reason);
});
})
socket.on('receiver-answer', (answer) => {
console.log(answer);
peerConection.setRemoteDescription(answer.sdp);
peerConection.ontrack = function (event) {
remoteVideo.srcObject = event.streams[0];
};
});
}
function prepareToReceiveOffer(socket, peerConection, targetID, from) {
socket.on('receiver-offer', (offer) => {
console.log(offer);
peerConection.setRemoteDescription(offer.sdp);
peerConection.createAnswer().then(function (answer) {
return peerConection.setLocalDescription(answer);
})
.then(function () {
socket.emit('send-answer', {
from: from,
target: targetID,
type: "send-answer",
sdp: peerConection.localDescription
});
});
peerConection.ontrack = function (event) {
remoteVideo.srcObject = event.streams[0];
};
navigator.mediaDevices.getUserMedia({ video: true, audio: false }).then((stream) => {
localVideo.srcObject = stream;
})
});
}
});
I just using socket.io I am handle the offer and answer then on my socket server I just set like this
socket.on('initiator', (init) => {
console.log(init);
io.to('video').emit('initiator', init);
});
socket.on('send-offer', offer => {
console.log('sending offer', offer);
socket.broadcast.emit('receiver-offer', offer);
});
socket.on('send-answer', answer => {
console.log('sending answer', answer);
socket.broadcast.emit('receiver-answer', answer);
});
socket.on('send-candidate', candidate => {
console.log(candidate);
socket.broadcast.emit('receiver-candidate',candidate);
});
I am get video remote on my receiver from the initiator but not in the initiator, I don't know what I miss for getting the remote video thanks so mush guys

The initiator calls addTrack(), but not the receiver doesn't, so this is only sending media one way.
In prepareToReceiveOffer you call getUserMedia() but never add resulting tracks to the peer connection. If you want a two-way call, it needs to call addTrack() as part of the offer/answer negotiation.
Just be sure to call getUserMedia() after setRemoteDescription to not miss ICE candidates:
function prepareToReceiveOffer(socket, peerConection, targetID, from) {
socket.on('receiver-offer', (offer) => {
console.log(offer);
peerConection.setRemoteDescription(offer.sdp)
.then(() => navigator.mediaDevices.getUserMedia({video: true, audio: false}))
.then(stream => {
localVideo.srcObject = stream;
for (const track of stream.getTracks()) {
peerConection.addTrack(track, stream);
}
return peerConection.createAnswer();
})
.then(function (answer) {
return peerConection.setLocalDescription(answer);
})
.then(function () {
socket.emit('send-answer', {
from: from,
target: targetID,
type: "send-answer",
sdp: peerConection.localDescription
});
})
.catch(err => console.log(err.message));
peerConection.ontrack = function (event) {
remoteVideo.srcObject = event.streams[0];
};
});
}

I get resolve it, in this particular case I my initiateSignaling function when I receiver the offer I has to include this
socket.on('receiver-answer', (answer) => {
console.log(answer);
peerConection.setRemoteDescription(answer.sdp)
.then(function () {
return navigator.mediaDevices.getUserMedia({video:true, audio: false});
})
.then(function (stream) {
return peerConection.addStream(stream);
})
peerConection.ontrack = function (event) {
remoteVideo.srcObject = event.streams[0];
};
});
now is working for me

Related

WebSocket return undefined after fetching user, but console.log prints the user

I've been working with a websocket to fetch users.
I open the connection and send the messages to get the data, but if I want to return that user and use it elsewhere, I get undefined, but when running console.log inside the function, it gives me the user.
Here is my code :
export function fetchUser(id: number) {
const connection = generateConnection();
connection.onopen = () => {
connection.send(
JSON.stringify(
'{"msg":"connect","version":"1","support":["1","pre2","pre1"]}',
),
);
connection.send(
JSON.stringify(
`{"msg":"method","id":"1","method":"Users.getUser","params":[${id}]}`,
),
);
};
connection.on('message', async (event) => {
const data = event.toString();
if (data[0] == 'a') {
const a = JSON.parse(JSON.parse(data.substring(1))[0]);
if (a.msg == 'result') {
if ('error' in a) {
console.log(a.error.error);
connection.close();
return null;
} else {
let user= a.result;
console.log(user) // returns the user
return user; // return undefined
}
}
}
});
}
console.log(fetchUser(1));
Given the details I have this should be at least close to something functional. I've added a number of comments where the exist code doesn't make sense.
const state = {
isReady: false,
}
const connection = generateConnection();
const sendMsg = (msg) => connection.send(JSON.stringify(msg))
connection.onopen = () => {
sendMsg({"msg": "connect", "version": "1", "support": ["1", "pre2", "pre1"]})
state.isReady = true; // not sure if this is true yet
};
export async function fetchUser(id: number) {
if (!state.isReady) {
throw new Error("Not ready yet")
}
sendMsg({"msg": "method", "id": "1", "method": "Users.getUser", "params": [id]})
return new Promise((resolve, reject) => {
connection.once('message', async (event) => {
// why event.toString()? what is it? Is this JSON data?
const data = event.toString();
// what are you doing here?
if (data[0] === 'a') {
// this much be wrong and has something to do with event.toString()
const a = JSON.parse(JSON.parse(data.substring(1))[0]);
// this is likely wrong too ie should be something like a.result && a.error
if (a.msg === 'result') {
if ('error' in a) {
console.log(a.error.error);
return resolve(null)
}
let user = a.result;
console.log(user) // returns the user
return resolve(user); // return undefined
}
}
});
})
}
fetchUser(1)
.then((user) => console.log(user))
.catch((err) => console.log(err))
I got inspired from your code and got something to work:
import { generateConnection } from './generate-connection';
const connection = generateConnection();
export async function fetchUser(id: number) {
return new Promise(function (resolve) {
console.log('Opening connection...');
connection.onopen = () => {
connection.send(
JSON.stringify(
'{"msg":"connect","version":"1","support":["1","pre2","pre1"]}',
),
);
console.log('Connection opened');
console.log('Sending message...');
connection.send(
JSON.stringify(
`{"msg":"method","id":"1","method":"Users.getUser","params":[${id}]}`,
),
);
};
connection.on('message', async (event) => {
// yes it gives json data;
const data = event.toString();
if (data[0] == 'a') {
// when the response come it's a string with a prefix 'a'
const a = JSON.parse(JSON.parse(data.substring(1))[0]);
if (a.msg == 'result') {
if ('error' in a) {
console.log(a.error.error);
return null;
} else {
resolve(a.result);
connection.close();
}
}
}
});
connection.on('error', function (error) {
console.log('Connection Error: ' + error.toString());
});
connection.on('close', function () {
console.log('echo-protocol Connection Closed');
});
});
}
fetchUser(1).then((data) => console.log(data.name));
The problem with one , is when I loop , I only get the first user
for (let i = 0; i < 10; i++) {
const data: any = await fetchUser(i);
console.log(data.name);
}
gives :
Opening connection
connection opened
sending message
Jack
Opening connection
connection opened
sending message
and it exits...

React Hook useEffect has missing dependencies: 'roomID 'and 'sotreId'. Either include them or remove the dependency array react-hooks/exhaustive-deps

I am not using socketData function outside the useEffect and then also, i am getting warning.I want to remove this warning without using // eslint-disable-next-line.
I am getting roomID and sotreID from parent Component from server and socket is the local server url
useEffect(() => {
const socketData = () => {
console.log('sotreId', sotreId);
setReceiverID(sotreId);
socketRef.current = socket;
console.log(socket);
socketRef.current.emit('mobileNumber', roomID);
navigator.mediaDevices.getUserMedia({ video: true, audio: false }).then(stream => {
backgroundVideo.current.srcObject = stream;
}).catch((error) => {
console.log("background error", error)
});
socketRef.current.on("yourID", (id) => {
console.log(id);
setYourID(id);
})
socketRef.current.on("allUsers", (users) => {
console.log(users);
setUsers(users);
})
}
socketData();
}, []);
You should add both roomId and storeId in the array of dependencies like so:
useEffect(() => {
const socketData = () => {
console.log('sotreId', sotreId);
setReceiverID(sotreId);
socketRef.current = socket;
console.log(socket);
socketRef.current.emit('mobileNumber', roomID);
navigator.mediaDevices.getUserMedia({ video: true, audio: false }).then(stream => {
backgroundVideo.current.srcObject = stream;
}).catch((error) => {
console.log("background error", error)
});
socketRef.current.on("yourID", (id) => {
console.log(id);
setYourID(id);
})
socketRef.current.on("allUsers", (users) => {
console.log(users);
setUsers(users);
})
}
socketData();
}, [roomeId, storeId]);

onaddstream event not called

I use WebRTC to connected 2 Chrome Browsers. I create offer on the first and send it via signalR to second client like this :
function initiate_call() {
callerPeerConn = new RTCPeerConnection(peerConnCfg);
callerPeerConn.ontrack = function (event) {
console.log('caller recived new stream');
remoteVideo.srcObject = event.streams[0];
console.log(event);
}
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(function (stream) {
localVideo.srcObject = stream;
for (const track of stream.getTracks()) {
callerPeerConn.addTrack(track, stream);
}
return callerPeerConn.createOffer();
})
.then(
function (offer) {
var off = new RTCSessionDescription(offer);
callerPeerConn.setLocalDescription(
new RTCSessionDescription(off),
function () {
// invite to video chat
console.log('send offer');
},
function (err) {
console.log(err.message);
}
)
});
}
When my second browser getting offer he use setLocalDescription and try to create answer than send it to caller like that :
function accept_send_answer(){
calleePeerConn = new RTCPeerConnection(peerConnCfg);
calleePeerConn.ontrack = function (event) {
console.log('callee accept offer and got streams');
remoteVideo.srcObject = event.streams[0];
}
calleePeerConn.setRemoteDescription(offer)
.then(function () {
return navigator.mediaDevices.getUserMedia({ audio: true, video: true });
})
.then(function (stream) {
localVideo.srcObject = stream;
for (const track of stream.getTracks()) {
calleePeerConn.addTrack(track, stream);
}
return calleePeerConn.createAnswer();
})
.then(function (answer) {
// sending answer
console.log("sending ansfer");
var remote_streams = calleePeerConn.getRemoteStreams();
var local_streams = calleePeerConn.getLocalStreams();
console.log("callee remote streams");
console.log(remote_streams);
console.log("callee local streams");
console.log(local_streams);
})
.catch(function (err) {
console.log(err.message);
});
}
UPD
After I changed my code, following the advice of a respected #jib, my local and remote streams on both sides was successfully added to RTCPeerConnection object. I successfully obtain following messanges in console : caller recived new stream and callee accept offer and got streams as well. Last problem is - why this code not working :
calleePeerConn.ontrack = function (event) {
console.log('callee accept offer and got streams');
remoteVideo.srcObject = event.streams[0];
}
video not played.
First, addStream and onaddstream are deprecated, and won't work in other browsers. Use addTrack and ontrack instead.
Second, timing.
You're calling peerConn.createOffer() before peerConn.addStream(stream) so tracks are not picked up.
Same with peerConn.createAnswer() before peerConn.addStream(stream).
Lastly, mixing callbacks and promises confuses the order of things here. Try:
const peerConn = new RTCPeerConnection(peerConnCfg);
peerConn.ontrack = function (event) {
alert('new stream added! ' + event.streams[0]);
}
function initiate_call() {
navigator.mediaDevices.getUserMedia({audio: true, video: true})
.then(function (stream) {
localVideo.srcObject = stream;
for (const track of stream.getTracks()) {
peerConn.addTrack(track, stream);
}
return peerConn.createOffer();
})
.then(function (offer) {
// signaling and invite
return peerConn.setLocalDescription(off);
})
.catch(function (err) {
console.log(err.message);
});
}
function accept_send_answer(offer) {
peerConn.setRemoteDescription(offer)
.then(function () {
return navigator.mediaDevices.getUserMedia({audio: true, video: true});
})
.then(function (stream) {
video.srcObject = stream;
for (const track of stream.getTracks()) {
peerConn.addTrack(track, stream);
}
return peerConn.createAnswer();
})
.then(function (answer) {
//signaling to caller and send answer
return peerConn.setLocalDescription(answer);
})
.catch(function (err) {
console.log(err.message);
});
}
Note that your code (and my reply) still lack critical pieces: ice candidate exchange, and you're not showing your setRemoteDescription(answer) code to complete the negotiation loop.
Note that most examples tend to use the same JS on both sides, like e.g. this working fiddle using iframe postMessage for signaling.

Used service workers with apache aliases not working

I want to add service worker to cache loaded resources in my application.
Let's imagin
My application is loading under https://domain/application
from that /application page i'm fetching resources from a server alias,
https://domain/mat-resources/applications/application1/dist/..
here is my register,
if (navigator.serviceWorker) {
navigator.serviceWorker.register('/mat-resources/applications/application1/
/service-worker.js', {scope: '/mat-resources/applications/application1/'}).then(function (registration) {
console.log("registration", registration);
}).catch(function (e) {
console.log(e);
});
} else {
console.log('Service Worker is not supported in this browser.')
}
this is the code I have added to service worker js
'use strict';
const VERSION = 'v1';
const PRECACHE = `precache-${VERSION}`;
const RUNTIME = `runtime-${VERSION}`;
const enableRuntimeCache = true;
const mode = 'cache-update';
const PRECACHE_URLS = [
'https://fonts.googleapis.com/css?family=Open+Sans:400,600|Roboto:400,500',
'./dist/js/vendor.bundle.js',
'./dist/js/app.bundle.js',
'./dist/css/styles.min.css'
];
let NetworkOnline = true;
self.addEventListener('install', event => {
event.waitUntil(
caches.open(PRECACHE).then(cache => {
cache.addAll(PRECACHE_URLS);
}).then(self.skipWaiting())
);
});
self.addEventListener('activate', event => {
const currentCaches = [PRECACHE, RUNTIME];
event.waitUntil(
caches.keys().then(cacheNames => {
return cacheNames.filter(cacheName => !currentCaches.includes(cacheName));
}).then(cachesToDelete => {
return Promise.all(cachesToDelete.map(cacheToDelete => {
return caches.delete(cacheToDelete);
}));
}).then(() => {
self.clients.claim();
})
);
});
self.addEventListener('fetch', event => {
if (event.request.url.startsWith(self.location.origin)) {
event.respondWith(fromCache(event.request));
if (isOnline()) {
if (mode === 'cache-update') {
event.waitUntil(
update(event.request)
/*.then(refresh)*/
.catch(errorHandler)
);
}
}
}
});
/*function setFromCache(request) {
console.log(self);
updateFromCache(true);
}*/
function fromCache(request) {
return caches.match(request).then(cachedResponse => {
if (cachedResponse) {
return cachedResponse;
}
if (isOnline()) {
if (enableRuntimeCache) {
return caches.open(RUNTIME).then(cache => {
return fetch(request).then(response => {
return cache.put(request, response.clone()).then(() => {
return response;
});
}).catch(errorHandler);
});
} else {
return fetch(request).then(response => {
return response;
});
}
}
});
}
function update(request) {
let asset = request.url.substr(request.url.lastIndexOf('/') + 1);
let openCache = (PRECACHE_URLS.some(val => val.indexOf(asset) >= 0)) ? PRECACHE : RUNTIME;
return caches.open(openCache).then(cache => {
return fetch(`${request.url }?${new Date().valueOf()}`).then(response => {
return cache.put(request, response.clone()).then(() => {
return response;
});
}).catch(errorHandler);
});
}
function refresh(response) {
return self.clients.matchAll().then(clients => {
clients.forEach(client => {
var message = {
type: 'refresh',
url: response.url,
eTag: response.headers.get('ETag')
};
client.postMessage(JSON.stringify(message));
});
});
}
function isOnline() {
return self.navigator.onLine;
}
function errorHandler(error) {
if (error instanceof TypeError) {
if (error.message.includes('Failed to fetch')) {
console.error('(FtF) Error caught:', error);
} else {
console.error('Error caught:', error);
}
}
}
After I refresh service worker is successfully, I can see service worker is well registerd but however resources are not chached.
Please help??
You have defined a scope when your register the service worker. This limits the access of the service worker to only handle fetches that are for resources that fall under the /mat-resources/applications/application1/**/* path
{scope: '/mat-resources/applications/application1/'}
If you want the service worker to handle resources at the root of the application /application you need to set the scope to /.
{scope: '/'}
You can read more about scopes on Web Fundamentals.

Trying to convert a script that involves webrtc into async/await failing

I am following this tutorial to make webrtc work. I would like to return the streams I get in resolve() to the component I call this getDrone() from. I created a returnStreamArray() function as a child promise which I tried to add as a then() to the stream to add it to the array, however I am stuck. I would appreciate any directions.
export default function getDrone() {
return new Promise((resolve, reject) => {
const drone = new Scaledrone('fBAkzbVAOmA2wbU0');
const roomName = 'observable-room';
const configuration = {
iceServers: [
{
urls: 'stun:stun.l.google.com:19302'
}
]
};
let room;
let pc;
const streamArr = [];
...
drone.on('open', error => {
if (error) {
console.error(error);
}
room = drone.subscribe(roomName);
room.on('open', error => {
if (error) {
onError(error);
}
});
..
..
pc.ontrack = event => {
const stream = event.streams[0];
streamArr.push(stream);
};
navigator.mediaDevices
.getUserMedia({
audio: true,
video: true
})
.then(stream => {
streamArr.push(stream);
stream.getTracks().forEach(track => pc.addTrack(track, stream));
}, onError)
.then(returnStreamArray => {
console.log(stream);
});
..
..
});
}
function returnStreamArray() {
return Promise.resolve({
streamArray: streamArr
});
}

Categories

Resources