Closed ismailsemihsenturk closed 1 year ago
I can workaround like that:
Server
socket.broadcast.emit("remoteAnswerForLocal", { remoteSdp: remoteSdp, socket: socket.id });
Client
socket.current.on("remoteAnswerForLocal", async (arg) => { if (arg.socket !== socket.current.id) { } });
But a permanent solution would be better.
I have taken a quick look at your repository, Socket.IO is working as expected, it isnt emitting back to the socket that sent it, the issue is due to the way you are connecting to the Socket.IO server, you make the connection in the component, but not inside of a useEffect, meaning that, everysingle time your app re-renders, it connects again with a new socket, and therefore new socket ID.
So you are emitting the event, which most likely triggers an app re-render (unsure, I haven't dived deep into your code)
Your app then creates a new socket, and your server responds to all sockets that didnt send the socket, which includes the new one you have just made.
Take a look at How to use with React, doesn't matter that youre using React Native, the principle is still the same.
Happy to give any further explinations.
@OlliePugh thank you for your answer. I tried to implement the flow as the documentation suggest. Seems like issue is gone for now. I can work with the rooms and emit events to the clients except the sender. But this new implementation has caused another issue. Now the "socket.on" listeners in the client side triggers multiple times. Since i'am trying to build a webrtc chat app this cause triggering the pc.setLocalDescription(offer) function multiple times and i get this error "[Unhandled promise rejection: Error: Failed to set local offer sdp: The order of m-lines in subsequent offer doesn't match order from previous offer/answer.]" error. I know this error probably has nothing with socket.io but i wonder why the client side listeners fires multiple times. Did i implement the structure wrong? I provide some code and console output:
Server
const app = express();
const server = require("http").Server(app);
const io = require("socket.io")(server);
const port = 3000;
const cors = require("cors");`
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(cors());
io.sockets.on('connection', function (socket) {
socket.on("create", (room) => {
socket.join(room);
});
socket.on("start", (arg) => {
console.log("room: " + JSON.stringify(arg, 0, 4));
socket.to(arg.room).emit("setLocalOffer");
});
socket.on("getLocalOffer", (arg) => {
console.log("getLocalOffer: " + JSON.stringify(arg, 0, 4));
socket.to(arg.room).emit("setRemoteAnswer", { offerSdp: arg.offerSdp, room: arg.room });
});
socket.on("getRemoteAnswer", (arg) => {
console.log("getRemoteAnswer: " + JSON.stringify(arg, 0, 4));
socket.to(arg.room).emit("setLocalAnswer", { answerSdp: arg.offerSdp, room: arg.room });
});
socket.on("exchangeICECandidates", (arg) => {
console.log("exchangeICECandidates: " + JSON.stringify(arg, 0, 4));
socket.to(arg.room).emit("getICECandidates", { candidate: arg.candidate, room: arg.room });
});
});
server.listen(port, () => console.log("server running on port:" + port));
Socket.js
import { io } from 'socket.io-client';
import { WEBSOCKET_URL } from '@env'
const connectionConfig = {
jsonp: false,
reconnection: true,
reconnectionDelay: 100,
reconnectionAttempts: 100000,
transports: ['websocket'],
};
export const socket = io(WEBSOCKET_URL, connectionConfig);
Client
// Initiate The Call
const startCall = async () => {
let hostId = Crypto.randomUUID();
roomTextInputRef.current.value = hostId;
socket.emit("create", hostId);
setRoomId(hostId);
setIsCallCreated(!isCallCreated);
};
// Join The Remote Call
const joinCall = async () => {
setIsCallJoined(!isCallJoined);
// Get the offer from signaling server and answer it
socket.emit("create", roomId);
socket.emit("start", { room: roomId });
};
socket.on("setLocalOffer", async (arg) => {
console.log("setLocalOffer");
const offerDescription = await peerConnection.current.createOffer();
await peerConnection.current.setLocalDescription(offerDescription);
socket.to(roomId).emit("getLocalOffer", { offerSdp: offerDescription, room: roomId });
});
socket.on("setRemoteAnswer", async (arg) => {
console.log("setRemoteAnswer");
const offerDescription = new RTCSessionDescription(arg.offerSdp);
await peerConnection.current.setRemoteDescription(offerDescription);
const answerDescription = await peerConnection.current.createAnswer();
await peerConnection.current.setLocalDescription(answerDescription);
socket.to(roomId).emit("getRemoteAnswer", { answerSdp: answerDescription, room: roomId });
});
socket.on("setLocalAnswer", async (arg) => {
console.log("setLocalAnswer");
const answerDescription = new RTCSessionDescription(arg.answerSdp);
await peerConnection.current.setRemoteDescription(answerDescription);
});
socket.on("getICECandidates", (arg) => {
console.log("getICECandidates");
peerConnection.current.addIceCandidate(arg.candidate);
});
CONSOLE OUTPUT
I see the rn-webrtc is debugging those messages, you have a similar issue with how you are adding event listeners, all of your peerConnection.current.addEventListeners
are being ran for every render cycle, most likely adding multiple listeners, yuou are also creating a new new RTCPeerConnection(peerConstraints);
every single render, I would advise having a read over the react life cycle docs as this you will need a fundamental understanding of this process before being able to work in React.
For the specifics of the issue you are facing now it may be what I have just mentioned, but it could be something else, your app.js
file is doing so much its really quite hard to debug, try and make use of React's component style and break out all the different functionalities into their own components.
Thanks. I turned back to the basics and its paid off. Now the program is working just fine.
Describe the bug socket.broadcast.emit("remoteAnswerForLocal", remoteSdp); The data is sent back to itself also.
To Reproduce Here's my repo for the reproduce: https://github.com/ismailsemihsenturk/React_Native_WebRTC_ChatApp you need at least 2 phone (1 emulator and 1 physical phone would do the work too). Please fill the following code example:
Socket.IO server version:
x.y.z
Server
Expected behavior socket.broadcast.emit() shouldn't send the event to the itself.
Platform:
Additional context "dependencies": { "expo": "~48.0.10", "expo-crypto": "^12.2.2", "expo-dev-client": "^2.1.6", "expo-splash-screen": "~0.18.1", "expo-status-bar": "~1.4.4", "react": "18.2.0", "react-native": "0.71.6", "react-native-dotenv": "^3.4.8", "react-native-webrtc": "^111.0.0", "socket.io-client": "^4.6.1" }, "devDependencies": { "@babel/core": "^7.20.0" },