import React, { useEffect, useContext, useRef } from 'react';
import { SocketContext } from "../../contexts/socketContext";
const Call = ({ myId, otherId, init }) => {
const socket = useContext(SocketContext);
const localStream = useRef();
const remoteStream = useRef();
const _pc = useRef(new RTCPeerConnection());
useEffect(() => {
navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then((stream) => {
localStream.current.srcObject = stream;
stream.getTracks().forEach((track) => {
_pc.current.addTrack(track, stream);
});
}).catch((err) => {
console.log(err);
});
if (init) {
createAndSendOffer()
}
_pc.current.onicecandidate = (e) => {
if (e.candidate) {
socket.emit("candidate", { from: myId, to: otherId, candidate: e.candidate });
}
}
_pc.current.ontrack = (e) => {
console.log("Hello");
if (e.streams) {
console.log(e.streams);
}
}
});
useEffect(() => {
socket.on("offer", (data) => {
createAndSendAnswer(data);
});
socket.on("answer", (data) => {
setAnswer(data.answer);
});
socket.on("candidate", (data) => {
_pc.current.addIceCandidate(new RTCIceCandidate(data.candidate));
});
});
async function setAnswer(answer) {
_pc.current.setRemoteDescription(new RTCSessionDescription(answer));
}
async function createAndSendOffer() {
const offer = await _pc.current.createOffer({ offerToReceiveAudio: true, offerToReceiveVideo: true });
socket.emit("offer", { from: myId, to: otherId, offer });
_pc.current.setLocalDescription(new RTCSessionDescription(offer));
}
async function createAndSendAnswer({ from, to, offer }) {
_pc.current.setRemoteDescription(new RTCSessionDescription(offer));
const answer = await _pc.current.createAnswer();
_pc.current.setLocalDescription(new RTCSessionDescription(answer));
socket.emit("answer", { from: myId, to: otherId, answer });
}
return (
<div>
<video autoPlay muted ref={localStream} />
<video autoPlay muted ref={remoteStream} />
</div>
)
}
export default Call
``
I am trying to make a video calling app but remote peer video is not getting.
Related
I am Creating a chat application everything is almost done I can send messages and the server is receiving the data but can't receive the data from the socket.io server
basically, I created a separate server that connects the clients it didn't connect to the database. I tried everything but couldn't help
SocketServer.js
const io = require('socket.io')(9739, {
cors: {
origin: "*",
}
})
let activeUsers = [];
io.on('connection', (socket) => {
console.log('New user connected');
socket.on('login', (data) => {
console.log(data);
if (!activeUsers.some((user) => user.id === data)) {
activeUsers.push({
id: data,
socketId: socket.id
});
}
// remove the active user that id is null
activeUsers = activeUsers.filter((user) => user.id !== null);
console.log(activeUsers);
io.emit('activeUsers', activeUsers);
});
socket.on("sendMessage",(data)=>{
const { receiverId } = data;
const receiver = activeUsers.find((user) => user.id === receiverId);
console.log("Sending Message to : ", receiver);
console.log(data);
if(receiver){
console.log("comming")
console.log(receiver.socketId);
// send message to the receiver
const RSocketId = receiver.socketId;
console.log("RSocketId", RSocketId);
io.to(RSocketId).emit("getMessage", {
data: data,
});
}
});
socket.on("end", () => {
console.log("end");
socket.disconnect();
});
socket.on('disconnect', () => {
console.log('User disconnected');
activeUsers = activeUsers.filter((user) => user.socketId !== socket.id);
console.log(activeUsers);
io.emit('activeUsers', activeUsers);
});
});
Client Side
import axios from "axios";
import React, { useRef } from "react";
import nookies from "nookies";
import Index from "./index";
import FriendsHolder from "../../components/Holders/FriendsHolder";
import FriendsDetails from "../../components/Holders/details-chats-holders/FriendsDetails";
import { useRouter } from "next/router";
import DmsComponent from "../../components/Holders/details-chats-holders/DmsComponent";
import { userDetails } from "../../libs/chats";
import SetUserName from "../../models/SetUserName";
import { io } from "socket.io-client";
const friends = ({ token }: any) => {
const router = useRouter();
const [isLoading, setIsLoading] = React.useState(false);
const [username, setusername] = React.useState(false);
const [sendMsg, setSendMsg] = React.useState(null);
const [receivedMsg, setReceivedMsg] = React.useState(null);
const socket = useRef<any>();
React.useEffect(() => {
const init = async () => {
const { data } = await userDetails(token);
if (
data &&
(data.data.username.length > 20 || data.data.username === "")
) {
setusername(true);
} else {
setusername(false);
socket.current = io("ws://localhost:9739");
socket?.current.emit("login", data.data?.id);
socket?.current.on("activeUsers", (users: any) => {
console.log("active users", users);
});
}
};
if (token) {
init();
}
}, []);
const handleLoading = () => {
setIsLoading(true);
};
const handleNotLoading = () => {
setIsLoading(false);
};
React.useEffect(() => {
handleNotLoading();
}, [isLoading]);
// Sending message through the socket server
React.useEffect(() => {
if (sendMsg !== null) {
socket.current?.emit("sendMessage", sendMsg);
}
}, [sendMsg]);
// Recieving Message through the socket server
React.useEffect(() => {
socket.current?.on("getMessage", (data: any) => {
setReceivedMsg(data);
});
}, []);
React.useEffect(() => {
console.log(receivedMsg);
}, [receivedMsg]);
return (
<Index>
{username ? (
<SetUserName />
) : (
<>
<FriendsHolder data={token} handleLoading={handleLoading} />
{router.asPath === "/app/friends" && <FriendsDetails token={token} />}
{router.asPath === `/app/friends?id=${router.query.id}` &&
!isLoading && (
<DmsComponent token={token} setSendMsg={setSendMsg} />
)}
</>
)}
</Index>
);
};
export default friends;
export const getServerSideProps = async (ctx: any) => {
const cookies = nookies.get(ctx);
const token = cookies.token;
if (!token) {
return {
redirect: {
destination: "/?login",
permanent: false,
},
};
}
return {
props: {
token: token || null,
},
};
};
I'm building a project using react native and webRTC with nodejs + ejs.
establish connections:
1- browser to browser works well.
2- device to browser works well.
3- browser to device does not work and here is the problem and all codes are the same for socket io and peer connections.
// REACT NATIVE PART
const [localStream, setLocalStream] = useState<MediaStream|null>(null);
const [remoteStream, setRemoteStream] = useState<MediaStream|null>(null);
const socket = io(utils.RAW_BACKEND_URL)
const peerConnection = new RTCPeerConnection({
iceServers: [
{
urls: ['stun:stun.l.google.com:19302']
}
]
})
useEffect(()=> {
peerConnection.onaddstream = (e) => {
setRemoteStream(e.stream);
}
socket.emit('join-room')
socket.on('calling-user', async (args)=> {
setOffer(JSON.stringify(args.offer))
await peerConnection.setRemoteDescription(new RTCSessionDescription(args.offer));
utils.showAlertMessage("Calling", "You have a call", [
{
text: "Call?",
onPress: async ()=> await answerCall()
},
{
text: "No",
}
])
})
socket.on('ic-candidate', async(args)=> {
await peerConnection.addIceCandidate(new RTCIceCandidate(args.candidate))
})
socket.on('answer-made', async (args)=> {
console.log("HERE");
await peerConnection.setRemoteDescription(new RTCSessionDescription(args.answer));
setShow(true)
})
}, [])
const getUserMedia = async (callAUser?:boolean) => {
let isFront = true, videoSourceId: any = null;
try {
const availableDevices = await mediaDevices.enumerateDevices();
let videoSourceId;
for (let i = 0; i < availableDevices.length; i++) {
const sourceInfo = availableDevices[i];
if (
sourceInfo.kind == 'videoinput' &&
sourceInfo.facing == (isFront ? 'front' : 'environment')
) {
videoSourceId = sourceInfo.deviceId;
}
}
const mediaStream = await mediaDevices.getUserMedia({
// audio: true,
video: {
mandatory: {
minWidth: 500,
minHeight: 300,
minFrameRate: 30,
},
facingMode: 'user',
optional: [{sourceId: videoSourceId}]
}
})
setLocalStream(mediaStream);
peerConnection.addStream(mediaStream);
if(callAUser){
await callUser();
}
}catch(err: any) {
utils.showAlertMessage("ERRORsss", err.message);
}
}
const callUser = async () => {
peerConnection.onicecandidate = e => {
if(e.candidate) {
socket.emit('candidate', {
candidate: e.candidate
})
}
}
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(new RTCSessionDescription(offer));
socket.emit('call-user', {
offer: offer
})
}
const answerCall = async () => {
await getUserMedia();
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(new RTCSessionDescription(answer));
socket.emit('make-answer', {
answer
})
}
return (
<View style={styles.stream}>
<Button title="Call" onPress={()=>getUserMedia(true)} />
<Button title="Answer" onPress={()=>answerCall()} />
{localStream != null &&
<RTCView
objectFit={"cover"}
streamURL={localStream.toURL()}
style={{height: '50%', borderWidth: 1, borderColor: 'red'}}
/>
}
{remoteStream != null && show ?
<RTCView
objectFit={"cover"}
streamURL={remoteStream.toURL()}
style={{height: '50%', borderWidth: 1, borderColor: 'blue'}}
/>
: <Text>{offer}</Text>
}
</View>
);
//js file for serving ejs page
const client = io("https://b277-2001-16a2-cb25-a800-f1da-b62e-7f94-42ee.ngrok.io");
const peerConnection = new RTCPeerConnection({
iceServers: [
{
urls: ['stun:stun.l.google.com:19302']
}
]
})
client.on('answer-made', async (args)=> {
await peerConnection.setRemoteDescription(new RTCSessionDescription(args.answer));
sdpAnswer.innerHTML = JSON.stringify(args.answer);
})
client.on('answer-made', async (args)=> {
await peerConnection.setRemoteDescription(new RTCSessionDescription(args.answer));
sdpAnswer.innerHTML = JSON.stringify(args.answer);
})
onst callUser = async () => {
await getMedia();
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(new RTCSessionDescription(offer));
peerConnection.onicecandidate = (e) => {
if(e.candidate) {
client.emit('candidate', {
candidate: e.candidate
})
}
}
client.emit('call-user', {
offer
})
}
// socket io part
client.join("q2");
client.on('join-room', (args)=> {
client.broadcast.to("q2").emit("user-joined", {
id: client.id
})
})
client.on("call-user", (args) => {
client.broadcast.to("q2").emit("calling-user", args);
});
client.on("make-answer", (args) => {
client.broadcast.to("q2").emit("answer-made", args);
});
client.on("candidate", (args) => {
client.broadcast.to("q2").emit("ic-candidate", args);
});
I hope you can help me what mistake I made and did not figure it.
Thanks in advance
I am trying to make a group video call app with the help of a youtube tutorial. I am using react and socket io,
But somehow its giving me the above error. Can't understand what exactly I am doing wrong.
Kindly correct me.
Attaching the code for reference:
Create room page- The homepage
import React from "react";
import { v1 as uuid } from "uuid";
import { useNavigate } from "react-router-dom";
const CreateRoom = (props) => {
const navigate = useNavigate();
function create() {
const id = uuid();
//props.history.push(`/room/${id}`);
navigate(`/room/${id}`);
}
return (
<button onClick={create}>Create room</button>
);
};
export default CreateRoom;
Room.js - This is the landing page once call gets started.
import React, { useEffect, useRef, useState } from "react";
import io from "socket.io-client";
import Peer from "simple-peer";
import styled from "styled-components";
import { useParams } from "react-router-dom";
const Container = styled.div`
padding: 20px;
display: flex;
height: 100vh;
width: 90%;
margin: auto;
flex-wrap: wrap;
`;
const StyledVideo = styled.video`
height: 40%;
width: 50%;
`;
const Video = (props) => {
const ref = useRef();
useEffect(() => {
props.peer.on("stream", (stream) => {
ref.current.srcObject = stream;
});
});
return <StyledVideo playsInline autoPlay ref={ref} />;
};
const videoConstraints = {
height: window.innerHeight / 2,
width: window.innerWidth / 2,
};
const Room = (props) => {
const [peers, setPeers] = useState([]);
const socketRef = useRef();
const userVideo = useRef();
const peersRef = useRef([]);
let {roomID} = useParams();
console.log(roomID);
useEffect(() => {
socketRef.current = io.connect("http://localhost:8000");
navigator.mediaDevices
.getUserMedia({ video: videoConstraints, audio: true })
.then((stream) => {
userVideo.current.srcObject = stream;
socketRef.current.emit("join room", roomID);
socketRef.current.on("all users", (users) => {
const peers = [];
users.forEach((userID) => {
const peer = createPeer(userID, socketRef.current.id, stream);
peersRef.current.push({
peerID: userID,
peer,
});
peers.push(peer);
});
setPeers(peers);
});
socketRef.current.on("user joined", (payload) => {
const peer = addPeer(payload.signal, payload.callerID, stream);
peersRef.current.push({
peerID: payload.callerID,
peer,
});
setPeers((users) => [...users, peer]);
});
socketRef.current.on("receiving returned signal", (payload) => {
const item = peersRef.current.find((p) => p.peerID === payload.id);
item.peer.signal(payload.signal);
});
});
});
function createPeer(userToSignal, callerID, stream) {
const peer = new Peer({
initiator: true,
trickle: false,
stream,
});
peer.on("signal", (signal) => {
socketRef.current.emit("sending signal", {
userToSignal,
callerID,
signal,
});
});
return peer;
}
function addPeer(incomingSignal, callerID, stream) {
const peer = new Peer({
initiator: false,
trickle: false,
stream,
});
peer.on("signal", (signal) => {
socketRef.current.emit("returning signal", { signal, callerID });
});
peer.signal(incomingSignal);
return peer;
}
return (
<Container>
<StyledVideo muted ref={userVideo} autoPlay playsInline />
{peers.map((peer, index) => {
return <Video key={index} peer={peer} />;
})}
</Container>
);
};
export default Room;
Now for server end, this is my server code:
require('dotenv').config();
const express = require("express");
const http = require("http");
const app = express();
const cors = require("cors");
const server = http.createServer(app);
const socket = require("socket.io");
const io = socket(server);
const users = {};
const socketToRoom = {};
app.use(cors);
io.on('connection', socket => {
socket.on("join room", roomID => {
if (users[roomID]) {
const length = users[roomID].length;
if (length === 4) {
socket.emit("room full");
return;
}
users[roomID].push(socket.id);
} else {
users[roomID] = [socket.id];
}
socketToRoom[socket.id] = roomID;
const usersInThisRoom = users[roomID].filter(id => id !== socket.id);
socket.emit("all users", usersInThisRoom);
});
socket.on("sending signal", payload => {
io.to(payload.userToSignal).emit('user joined', { signal: payload.signal, callerID: payload.callerID });
});
socket.on("returning signal", payload => {
io.to(payload.callerID).emit('receiving returned signal', { signal: payload.signal, id: socket.id });
});
socket.on('disconnect', () => {
const roomID = socketToRoom[socket.id];
let room = users[roomID];
if (room) {
room = room.filter(id => id !== socket.id);
users[roomID] = room;
}
});
});
server.listen(process.env.PORT || 8000, () => console.log('server is running on port 8000'));
This is the link for youtube tutorial:
https://www.youtube.com/watch?v=R1sfHPwEH7A&t=154s
I'm having an issue with connecting my websocket on port 7777 to my aws deployment. I am new to sockets and deployment. I have my main port 8081 hooked up, but having issues with the websocket. I've been at this for a day and would like some pointers! Thanks!
Currently, receiving this error:
React code
import React from 'react';
import openSocket from 'socket.io-client';
let socket = openSocket('http://my-api.us-east-2.elasticbeanstalk.com:7777', { transports: ['websocket'] });
export class HomePage extends React.Component {
state = {
channels: null,
channelSelected: false,
socket: null,
typers: {},
channel: 1,
messages: [],
msg: ''
}
socket;
componentDidMount() {
}
componentDidUpdate() {
if (this.props.username && !this.state.channelSelected) {
this.configureSocket();
this.setState({ channel: 1, channelSelected: true });
this.socket.emit('joinChannel', { channel: 1, username: this.props.username });
}
}
configureSocket = () => {
socket.on('connection', () => {
if (this.state.channel) {
this.handleChannelSelect(this.state.channel.id);
}
});
socket.on('incomingChat', username => {
let typers = this.state.typers;
if (!typers[username]) {
typers[username] = 1;
this.setState({ typers })
}
});
socket.on('clearingChat', username => {
let typers = this.state.typers;
delete typers[username]
this.setState({ typers });
});
socket.on('incomingMessage', details => {
let messages = this.state.messages;
let typers = this.state.typers;
delete typers[details.username]
messages.push(details);
this.setState({ messages, typers });
})
socket.on('channel', channel => {
let channels = this.state.channels;
channels.forEach(c => {
if (c.id === channel.id) {
c.participants = channel.participants;
}
});
this.setState({ channels });
});
socket.on('message', message => {
let channels = this.state.channels
channels.forEach(c => {
if (c.id === message.channel_id) {
if (!c.messages) {
c.messages = [message];
} else {
c.messages.push(message);
}
}
});
this.setState({ channels });
});
this.socket = socket;
}
handleChannelSelect = e => {
e.preventDefault();
this.setState({ channel: 1 });
this.socket.emit('leaveChannel', this.props.username);
}
handleSendMessage = e => {
e.preventDefault();
this.socket.emit('send-message', { msg: this.state.msg, username: this.props.username, channel: this.state.channel });
this.setState({ msg: '' });
}
handleChange = e => {
const { value } = e.target;
this.setState({ msg: value });
if (!value) this.socket.emit('addingMessage', { username: this.props.username, msg: 'cleared' });
if(value) this.socket.emit('addingMessage', { username: this.props.username, msg: value });
}
render() {
return (
<div className='chat-app'>
<form onSubmit={this.handleSendMessage}>
<input type="text" onChange={this.handleChange} value={this.state.msg} />
</form>
<button onClick={this.handleChannelSelect}></button>
{ this.state.messages.length > 0 && this.state.messages.map(({ username, msg }) => <p key={Math.random()}>{`${username}: ${msg}`}</p>) }
{Object.keys(this.state.typers).length > 0 && Object.keys(this.state.typers).map(el => el !== this.props.username && <p>{`${el} typing....`}</p>)}
</div>
);
}
}
server code
const app = require("./app");
const socketio = require('socket.io');
const express = require('express');
const http = require('http');
const db = require("./db");
const AWS = require("aws-sdk");
const CryptoJS = require("crypto-js");
const em = express();
const server = http.createServer(em);
const chatPort = process.env.LIVE_CHAT_PORT || 7777;
const io = socketio(server);
server.listen(chatPort, () => {
console.log(`Live Chat sock running on port ${chatPort}`)
});
app.listen(process.env.PORT || 8081, () => {
console.log("Listening on PORT 8081");
});
io.on('connection', socket => {
let user;
socket.on('joinChannel', async ({ username, channel }) => {
user = userJoin(socket.id, username, channel);
socket.on('addingMessage', details => {
const { username, msg } = details;
if (msg === 'cleared') {
io.to(user.room).emit('clearingChat', username);
} else {
io.to(user.room).emit('incomingChat', username);
}
})
socket.join(user.room);
});
socket.on('send-message', async details => {
const { msg, username, channel } = details;
let em = await db.query(`
INSERT INTO messages(conversation_id, user_id, shared_post, message, posted)
VALUES($1, $2, null, $3, current_timestamp)
RETURNING id;
`, [channel, username, msg])
io.to(user.room).emit('incomingMessage', details)
})
socket.on('leaveChannel', username => {
const user = userLeave(username);
socket.disconnect();
});
});
I have three rooms General, TypeScript and Nest. I'am joining General room in the first and second browser tab. When I decide to leave General from the second tab and join TypeScript room I still get the messages from General even though I should have left it. The bug occures when you switch to room that has been in use by other client and leave it. I'am using NodeJs, Socket.io, NestJS and React.
Server
#WebSocketGateway()
export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
#WebSocketServer() server: Server;
private logger: Logger = new Logger('ChatGateway');
#SubscribeMessage('msgToServer')
handleMessage(client: Socket, message: { sender: string, room: string, message: string }): void {
this.server.to(message.room).emit('msgToClient', message);
this.logger.log(`msgToClient: ${message}`);
}
#SubscribeMessage('joinRoom')
handleRoomJoin(client: Socket, room: string ) {
client.join(room);
client.emit('joinedRoom', room);
this.logger.log(`Client joined ${room}`);
}
afterInit(server: Server) {
this.logger.log('Init');
}
handleDisconnect(client: Socket) {
this.logger.log(`Client disconnected: ${client.id}`);
}
handleConnection(client: Socket, ...args: any[]) {
this.logger.log(`Client connected: ${client.id}`);
}
#SubscribeMessage('leaveRoom')
handleRoomLeave(client: Socket, room: string ) {
console.log(client.id);
/* console.log(client.rooms);
console.log(client.adapter.rooms); */
client.leave(room);
/* console.log(room); */
/* client.rooms = {};
delete client.adapter.rooms[room]; */
client.emit('leftRoom', room);
this.logger.log(`Client left ${room}`);
/* console.log(client.adapter.rooms);
console.log(client.rooms); */
// console.log(client.adapter.rooms)
}
}
Client
const [state, setState] = useState({ sender: "", room: "", message: "" });
const [chat, setChat] = useState([
{ sender: "Peter", room: "General", message: "test" },
]);
const socket = io(BASE_URL);
const [room, setRoom] = useState({
General: false,
TypeScript: false,
NestJS: false,
});
console.log(room);
useEffect(() => {
socket.on("msgToClient", (msg) => {
setChat([...chat, { ...msg }]);
});
});
const onTextChange = (e) => {
setState({ ...state, [e.target.name]: e.target.value });
};
const onMessageSubmit = (e) => {
e.preventDefault();
const { sender, room, message } = state;
socket.emit("msgToServer", { sender, room, message });
setState({ message: "", sender: "", room: "" });
};
const toggleRoomMembership = (chatroom) => {
const isMemberOfActiveRoom = (chatroom) => {
return room[chatroom];
};
if (isMemberOfActiveRoom(chatroom)) {
setRoom({ ...room, [chatroom]: false });
socket.emit("leaveRoom", chatroom);
} else {
setRoom({ ...room, [chatroom]: true });
socket.emit("joinRoom", chatroom);
}
};
const renderChat = () => {
return chat.map(({ sender, message }, index) => (
<div key={index}>
<h3>
{sender}: <span>{message}</span>
</h3>
</div>
));
};
Turns out the solution is simple. Put the socket into the useEffect and create state for it.
const [socket, setSocket] = useState({});
useEffect(() => {
const socket = io(BASE_URL);
setSocket(socket);
socket.on("msgToClient", (msg) => {
setChat([...chat, { ...msg }]);
});
}, []);