Commit 655aefd3 authored by Kim, Chaerin's avatar Kim, Chaerin
Browse files

아직병합금지!

parent 0eb44346
......@@ -14,6 +14,7 @@
"react-dom": "^17.0.2",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"socket.io-client": "^4.1.2",
"web-vitals": "^1.0.1"
},
"scripts": {
......
......@@ -15,7 +15,7 @@ function App() {
<Route exact path="/user" component={HomeUserPage} />
<Route path="/profile/:id/update" component={InfoUpdatePage} />
<Route path="/profile/:id" component={ProfilePage} />
<Route path="/room/:id/:channel" component={RoomPage} />
<Route path="/room/:roomId/:channelId" component={RoomPage} />
</Switch>
{/* </AuthProvider> */}
</Router>
......
import React, { useState } from "react";
import io from "socket.io-client";
import { useRef } from "react";
import { useEffect } from "react";
import Video from "./Video";
import { useParams } from "react-router-dom";
const Screen = () => {
const [socket, setSocket] = useState(null);
const [users, setUsers] = useState([]);
const { roomId, channelId } = useParams();
let localVideoRef = useRef(null);
let sendPC;
let receivePCs;
// 방화벽 등의 보호장치를 거쳐 ip로 연결하기 위한 설정
const pc_config = {
iceServers: [
// {
// urls: 'stun:[STUN_IP]:[PORT]',
// 'credentials': '[YOR CREDENTIALS]',
// 'username': '[USERNAME]'
// },
{
urls: "stun:stun.l.google.com:19302",
},
],
};
useEffect(() => {
let newSocket = io.connect("http://localhost:8080");
let localStream;
//
newSocket.on("userEnter", (data) => {
createReceivePC(data.id, newSocket);
});
newSocket.on("allUsers", (data) => {
let len = data.users.length;
for (let i = 0; i < len; i++) {
createReceivePC(data.users[i].id, newSocket);
}
});
newSocket.on("userExit", (data) => {
receivePCs[data.id].close();
delete receivePCs[data.id];
setUsers((users) => users.filter((user) => user.id !== data.id));
});
newSocket.on("getSenderAnswer", async (data) => {
try {
console.log("get sender answer");
console.log(data.sdp);
await sendPC.setRemoteDescription(new RTCSessionDescription(data.sdp));
} catch (error) {
console.log(error);
}
});
newSocket.on("getSenderCandidate", async (data) => {
try {
console.log("get sender candidate");
if (!data.candidate) return;
sendPC.addIceCandidate(new RTCIceCandidate(data.candidate));
console.log("candidate add success");
} catch (error) {
console.log(error);
}
});
newSocket.on("getReceiverAnswer", async (data) => {
try {
console.log(`get socketID(${data.id})'s answer`);
let pc = receivePCs[data.id];
await pc.setRemoteDescription(data.sdp);
console.log(`socketID(${data.id})'s set remote sdp success`);
} catch (error) {
console.log(error);
}
});
newSocket.on("getReceiverCandidate", async (data) => {
try {
console.log(data);
console.log(`get socketID(${data.id})'s candidate`);
let pc = receivePCs[data.id];
if (!data.candidate) return;
pc.addIceCandidate(new RTCIceCandidate(data.candidate));
console.log(`socketID(${data.id})'s candidate add success`);
} catch (error) {
console.log(error);
}
});
setSocket(newSocket);
navigator.mediaDevices
.getUserMedia({
audio: true,
video: {
width: 375,
height: 260,
},
})
.then((stream) => {
if (localVideoRef.current) localVideoRef.current.srcObject = stream;
localStream = stream;
sendPC = createSenderPeerConnection(newSocket, localStream);
createSenderOffer(newSocket);
newSocket.emit("joinRoom", {
id: newSocket.id,
roomID: roomId,
});
})
.catch((error) => {
console.log(`getUserMedia error: ${error}`);
});
}, []);
const createReceivePC = (id, newSocket) => {
try {
console.log(`socketID(${id}) user entered`);
let pc = createReceiverPeerConnection(id, newSocket);
createReceiverOffer(pc, newSocket, id);
} catch (error) {
console.log(error);
}
};
const createSenderOffer = async (newSocket) => {
try {
let sdp = await sendPC.createOffer({
offerToReceiveAudio: false,
offerToReceiveVideo: false,
});
console.log("create sender offer success");
await sendPC.setLocalDescription(new RTCSessionDescription(sdp));
newSocket.emit("senderOffer", {
sdp,
senderSocketID: newSocket.id,
roomID: roomId,
});
} catch (error) {
console.log(error);
}
};
const createReceiverOffer = async (pc, newSocket, senderSocketID) => {
try {
let sdp = await pc.createOffer({
offerToReceiveAudio: true,
offerToReceiveVideo: true,
});
console.log("create receiver offer success");
await pc.setLocalDescription(new RTCSessionDescription(sdp));
newSocket.emit("receiverOffer", {
sdp,
receiverSocketID: newSocket.id,
senderSocketID,
roomID: roomId,
});
} catch (error) {
console.log(error);
}
};
const createSenderPeerConnection = (newSocket, localStream) => {
let pc = new RTCPeerConnection(pc_config);
pc.onicecandidate = (e) => {
if (e.candidate) {
console.log("sender PC onicecandidate");
newSocket.emit("senderCandidate", {
candidate: e.candidate,
senderSocketID: newSocket.id,
});
}
};
pc.oniceconnectionstatechange = (e) => {
console.log(e);
};
if (localStream) {
console.log("localstream add");
localStream.getTracks().forEach((track) => {
pc.addTrack(track, localStream);
});
} else {
console.log("no local stream");
}
// return pc
return pc;
};
const createReceiverPeerConnection = (socketID, newSocket) => {
let pc = new RTCPeerConnection(pc_config);
// add pc to peerConnections object
receivePCs = { ...receivePCs, [socketID]: pc };
pc.onicecandidate = (e) => {
if (e.candidate) {
console.log("receiver PC onicecandidate");
newSocket.emit("receiverCandidate", {
candidate: e.candidate,
receiverSocketID: newSocket.id,
senderSocketID: socketID,
});
}
};
pc.oniceconnectionstatechange = (e) => {
console.log(e);
};
pc.ontrack = (e) => {
console.log("ontrack success");
setUsers((oldUsers) => oldUsers.filter((user) => user.id !== socketID));
setUsers((oldUsers) => [
...oldUsers,
{
id: socketID,
stream: e.streams[0],
},
]);
};
// return pc
return pc;
};
return (
<div className="container">
<div className="row">
<div className="col" style={{ backgroundColor: '#FCF4FF' }}>
<p className="m-2" style={{ fontWeight: 'bold', color: '#4A4251', fontSize: '20px' }}>
스크린
</p>
<div className="col m-5"></div>
</div>
</div>
<div>
{console.log(users)}
<video
style={{
display: "flex",
justifyContent: "center",
width: 375,
height: 260,
backgroundColor: "black",
}}
muted
ref={localVideoRef}
autoPlay
></video>
{users.map((user, index) => {
return <Video key={index} stream={user.stream} />;
})}
</div>
)
}
);
};
export default Screen
export default Screen;
import React, { useEffect, useRef, useState } from "react";
const Video = ({ stream, muted }) => {
const ref = useRef(null);
const [isMuted, setIsMuted] = useState(false);
useEffect(() => {
if (ref.current) ref.current.srcObject = stream;
if (muted) setIsMuted(muted);
});
return (
<div>
<video ref={ref} muted={isMuted} autoPlay></video>
</div>
);
};
export default Video;
let http = require('http');
let express = require('express');
let cors = require('cors');
let socketio = require('socket.io');
let wrtc = require('wrtc');
const app = express();
const server = http.createServer(app);
app.use(cors());
let receiverPCs = {};
let senderPCs = {};
let users = {};
let socketToRoom = {};
const pc_config = {
"iceServers": [
// {
// urls: 'stun:[STUN_IP]:[PORT]',
// 'credentials': '[YOR CREDENTIALS]',
// 'username': '[USERNAME]'
// },
{
urls : 'stun:stun.l.google.com:19302'
}
]
}
const isIncluded = (array, id) => {
let len = array.length;
for (let i = 0; i < len; i++) {
if (array[i].id === id) return true;
}
return false;
}
const createReceiverPeerConnection = (socketID, socket, roomID) => {
let pc = new wrtc.RTCPeerConnection(pc_config);
if (receiverPCs[socketID]) receiverPCs[socketID] = pc;
else receiverPCs = {...receiverPCs, [socketID]: pc};
pc.onicecandidate = (e) => {
//console.log(`socketID: ${socketID}'s receiverPeerConnection icecandidate`);
socket.to(socketID).emit('getSenderCandidate', {
candidate: e.candidate
});
}
pc.oniceconnectionstatechange = (e) => {
//console.log(e);
}
pc.ontrack = (e) => {
if (users[roomID]) {
if (!isIncluded(users[roomID], socketID)) {
users[roomID].push({
id: socketID,
stream: e.streams[0]
});
} else return;
} else {
users[roomID] = [{
id: socketID,
stream: e.streams[0]
}];
}
socket.broadcast.to(roomID).emit('userEnter', {id: socketID});
}
return pc;
}
const createSenderPeerConnection = (receiverSocketID, senderSocketID, socket, roomID) => {
let pc = new wrtc.RTCPeerConnection(pc_config);
if (senderPCs[senderSocketID]) {
senderPCs[senderSocketID].filter(user => user.id !== receiverSocketID);
senderPCs[senderSocketID].push({id: receiverSocketID, pc: pc});
}
else senderPCs = {...senderPCs, [senderSocketID]: [{id: receiverSocketID, pc: pc}]};
pc.onicecandidate = (e) => {
//console.log(`socketID: ${receiverSocketID}'s senderPeerConnection icecandidate`);
socket.to(receiverSocketID).emit('getReceiverCandidate', {
id: senderSocketID,
candidate: e.candidate
});
}
pc.oniceconnectionstatechange = (e) => {
//console.log(e);
}
const sendUser = users[roomID].filter(user => user.id === senderSocketID);
sendUser[0].stream.getTracks().forEach(track => {
pc.addTrack(track, sendUser[0].stream);
});
return pc;
}
const getOtherUsersInRoom = (socketID, roomID) => {
let allUsers = [];
if (!users[roomID]) return allUsers;
let len = users[roomID].length;
for (let i = 0; i < len; i++) {
if (users[roomID][i].id === socketID) continue;
allUsers.push({id: users[roomID][i].id});
}
return allUsers;
}
const deleteUser = (socketID, roomID) => {
let roomUsers = users[roomID];
if (!roomUsers) return;
roomUsers = roomUsers.filter(user => user.id !== socketID);
users[roomID] = roomUsers;
if (roomUsers.length === 0) {
delete users[roomID];
}
delete socketToRoom[socketID];
}
const closeRecevierPC = (socketID) => {
if (!receiverPCs[socketID]) return;
receiverPCs[socketID].close();
delete receiverPCs[socketID];
}
const closeSenderPCs = (socketID) => {
if (!senderPCs[socketID]) return;
let len = senderPCs[socketID].length;
for (let i = 0; i < len; i++) {
senderPCs[socketID][i].pc.close();
let _senderPCs = senderPCs[senderPCs[socketID][i].id];
let senderPC = _senderPCs.filter(sPC => sPC.id === socketID);
if (senderPC[0]) {
senderPC[0].pc.close();
senderPCs[senderPCs[socketID][i].id] = _senderPCs.filter(sPC => sPC.id !== socketID);
}
}
delete senderPCs[socketID];
}
const io = socketio.listen(server);
io.sockets.on('connection', (socket) => {
socket.on('joinRoom', (data) => {
try {
let allUsers = getOtherUsersInRoom(data.id, data.roomID);
io.to(data.id).emit('allUsers', { users: allUsers });
} catch (error) {
console.log(error);
}
});
socket.on('senderOffer', async(data) => {
try {
socketToRoom[data.senderSocketID] = data.roomID;
let pc = createReceiverPeerConnection(data.senderSocketID, socket, data.roomID);
await pc.setRemoteDescription(data.sdp);
let sdp = await pc.createAnswer({offerToReceiveAudio: true, offerToReceiveVideo: true});
await pc.setLocalDescription(sdp);
socket.join(data.roomID);
io.to(data.senderSocketID).emit('getSenderAnswer', { sdp });
} catch (error) {
console.log(error);
}
});
socket.on('senderCandidate', async(data) => {
try {
let pc = receiverPCs[data.senderSocketID];
await pc.addIceCandidate(new wrtc.RTCIceCandidate(data.candidate));
} catch (error) {
console.log(error);
}
});
socket.on('receiverOffer', async(data) => {
try {
let pc = createSenderPeerConnection(data.receiverSocketID, data.senderSocketID, socket, data.roomID);
await pc.setRemoteDescription(data.sdp);
let sdp = await pc.createAnswer({offerToReceiveAudio: false, offerToReceiveVideo: false});
await pc.setLocalDescription(sdp);
io.to(data.receiverSocketID).emit('getReceiverAnswer', { id: data.senderSocketID, sdp });
} catch (error) {
console.log(error);
}
});
socket.on('receiverCandidate', async(data) => {
try {
const senderPC = senderPCs[data.senderSocketID].filter(sPC => sPC.id === data.receiverSocketID);
await senderPC[0].pc.addIceCandidate(new wrtc.RTCIceCandidate(data.candidate));
} catch (error) {
console.log(error);
}
});
socket.on('disconnect', () => {
try {
let roomID = socketToRoom[socket.id];
deleteUser(socket.id, roomID);
closeRecevierPC(socket.id);
closeSenderPCs(socket.id);
socket.broadcast.to(roomID).emit('userExit', {id: socket.id});
} catch (error) {
console.log(error);
}
});
});
server.listen(process.env.PORT || 8080, () => {
console.log('server running on 8080');
})
\ No newline at end of file
......@@ -3,23 +3,22 @@
"version": "1.0.0",
"description": "Streaming Service",
"main": "index.js",
"dependencies": {
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"nodemon": "^2.0.7",
"npm": "^7.18.1"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://compmath.korea.ac.kr/gitlab/research/bora_it.git"
"start": "nodemon index.js",
"dev": "nodemon src/index.ts",
"build": "tsc -p ."
},
"keywords": [],
"author": "",
"license": "ISC"
"license": "ISC",
"dependencies": {
"cors": "2.8.5",
"express": "4.17.1",
"http": "0.0.1-security",
"socket.io": "2.3.0",
"wrtc": "0.4.6"
},
"devDependencies": {
"nodemon": "2.0.7"
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment