-
-
Save tsh-code/5d34542fe5274341439ef92de7861cd3 to your computer and use it in GitHub Desktop.
import express, { Application } from "express"; | |
import socketIO, { Server as SocketIOServer } from "socket.io"; | |
import { createServer, Server as HTTPServer } from "http"; | |
export class Server { | |
private httpServer: HTTPServer; | |
private app: Application; | |
private io: SocketIOServer; | |
private readonly DEFAULT_PORT = 5000; | |
constructor() { | |
this.initialize(); | |
this.handleRoutes(); | |
this.handleSocketConnection(); | |
} | |
private initialize(): void { | |
this.app = express(); | |
this.httpServer = createServer(this.app); | |
this.io = socketIO(this.httpServer); | |
} | |
private handleRoutes(): void { | |
this.app.get("/", (req, res) => { | |
res.send(`<h1>Hello World</h1>`); | |
}); | |
} | |
private handleSocketConnection(): void { | |
this.io.on("connection", socket => { | |
console.log("Socket connected."); | |
}); | |
} | |
public listen(callback: (port: number) => void): void { | |
this.httpServer.listen(this.DEFAULT_PORT, () => | |
callback(this.DEFAULT_PORT) | |
); | |
} | |
} |
async function callUser(socketId) { | |
const offer = await peerConnection.createOffer(); | |
await peerConnection.setLocalDescription(new RTCSessionDescription(offer)); | |
socket.emit("call-user", { | |
offer, | |
to: socketId | |
}); | |
} |
socket.on("call-user", data => { | |
socket.to(data.to).emit("call-made", { | |
offer: data.offer, | |
socket: socket.id | |
}); | |
}); |
function createUserItemContainer(socketId) { | |
const userContainerEl = document.createElement("div"); | |
const usernameEl = document.createElement("p"); | |
userContainerEl.setAttribute("class", "active-user"); | |
userContainerEl.setAttribute("id", socketId); | |
usernameEl.setAttribute("class", "username"); | |
usernameEl.innerHTML = `Socket: ${socketId}`; | |
userContainerEl.appendChild(usernameEl); | |
userContainerEl.addEventListener("click", () => { | |
unselectUsersFromList(); | |
userContainerEl.setAttribute("class", "active-user active-user--selected"); | |
const talkingWithInfo = document.getElementById("talking-with-info"); | |
talkingWithInfo.innerHTML = `Talking with: "Socket: ${socketId}"`; | |
callUser(socketId); | |
}); | |
return userContainerEl; | |
} |
navigator.getUserMedia( | |
{ video: true, audio: true }, | |
stream => { | |
const localVideo = document.getElementById("local-video"); | |
if (localVideo) { | |
localVideo.srcObject = stream; | |
} | |
}, | |
error => { | |
console.warn(error.message); | |
} | |
); |
private configureApp(): void { | |
this.app.use(express.static(path.join(__dirname, "../public"))); | |
} |
<!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" /> | |
<title>Dogeller</title> | |
<link | |
href="https://fonts.googleapis.com/css?family=Montserrat:300,400,500,700&display=swap" | |
rel="stylesheet" | |
/> | |
<link rel="stylesheet" href="./styles.css" /> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script> | |
</head> | |
<body> | |
<div class="container"> | |
<header class="header"> | |
<div class="logo-container"> | |
<img src="./img/doge.png" alt="doge logo" class="logo-img" /> | |
<h1 class="logo-text"> | |
Doge<span class="logo-highlight">ller</span> | |
</h1> | |
</div> | |
</header> | |
<div class="content-container"> | |
<div class="active-users-panel" id="active-user-container"> | |
<h3 class="panel-title">Active Users:</h3> | |
</div> | |
<div class="video-chat-container"> | |
<h2 class="talk-info" id="talking-with-info"> | |
Select active user on the left menu. | |
</h2> | |
<div class="video-container"> | |
<video autoplay class="remote-video" id="remote-video"></video> | |
<video autoplay muted class="local-video" id="local-video"></video> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script src="./scripts/index.js"></script> | |
</body> | |
</html> |
import { Server } from "./server"; | |
const server = new Server(); | |
server.listen(port => { | |
console.log(`Server is listening on http://localhost:${port}`); | |
}); |
private activeSockets: string[] = []; |
socket.on("make-answer", data => { | |
socket.to(data.to).emit("answer-made", { | |
socket: socket.id, | |
answer: data.answer | |
}); | |
}); |
npm init |
socket.on("call-made", async data => { | |
await peerConnection.setRemoteDescription( | |
new RTCSessionDescription(data.offer) | |
); | |
const answer = await peerConnection.createAnswer(); | |
await peerConnection.setLocalDescription(new RTCSessionDescription(answer)); | |
socket.emit("make-answer", { | |
answer, | |
to: data.socket | |
}); | |
}); |
socket.on("answer-made", async data => { | |
await peerConnection.setRemoteDescription( | |
new RTCSessionDescription(data.answer) | |
); | |
if (!isAlreadyCalling) { | |
callUser(data.socket); | |
isAlreadyCalling = true; | |
} | |
}); |
socket.on("update-user-list", ({ users }) => { | |
updateUserList(users); | |
}); | |
socket.on("remove-user", ({ socketId }) => { | |
const elToRemove = document.getElementById(socketId); | |
if (elToRemove) { | |
elToRemove.remove(); | |
} | |
}); |
{ | |
"scripts": { | |
"start": "ts-node src/index.ts", | |
"dev": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts" | |
}, | |
"devDependencies": { | |
"@types/express": "^4.17.2", | |
"@types/socket.io": "^2.1.4", | |
"nodemon": "^1.19.4", | |
"ts-node": "^8.4.1", | |
"typescript": "^3.7.2" | |
}, | |
"dependencies": { | |
"express": "^4.17.1", | |
"socket.io": "^2.3.0" | |
} | |
} |
navigator.getUserMedia( | |
{ video: true, audio: true }, | |
stream => { | |
const localVideo = document.getElementById("local-video"); | |
if (localVideo) { | |
localVideo.srcObject = stream; | |
} | |
stream.getTracks().forEach(track => peerConnection.addTrack(track, stream)); | |
}, | |
error => { | |
console.warn(error.message); | |
} | |
); |
const { RTCPeerConnection, RTCSessionDescription } = window; |
private initialize(): void { | |
this.app = express(); | |
this.httpServer = createServer(this.app); | |
this.io = socketIO(this.httpServer); | |
this.configureApp(); | |
this.handleSocketConnection(); | |
} |
peerConnection.ontrack = function({ streams: [stream] }) { | |
const remoteVideo = document.getElementById("remote-video"); | |
if (remoteVideo) { | |
remoteVideo.srcObject = stream; | |
} | |
}; |
const socket = io.connect("localhost:5000"); |
this.io.on("connection", socket => { | |
const existingSocket = this.activeSockets.find( | |
existingSocket => existingSocket === socket.id | |
); | |
if (!existingSocket) { | |
this.activeSockets.push(socket.id); | |
socket.emit("update-user-list", { | |
users: this.activeSockets.filter( | |
existingSocket => existingSocket !== socket.id | |
) | |
}); | |
socket.broadcast.emit("update-user-list", { | |
users: [socket.id] | |
}); | |
} | |
} |
socket.on("disconnect", () => { | |
this.activeSockets = this.activeSockets.filter( | |
existingSocket => existingSocket !== socket.id | |
); | |
socket.broadcast.emit("remove-user", { | |
socketId: socket.id | |
}); | |
}); |
function updateUserList(socketIds) { | |
const activeUserContainer = document.getElementById("active-user-container"); | |
socketIds.forEach(socketId => { | |
const alreadyExistingUser = document.getElementById(socketId); | |
if (!alreadyExistingUser) { | |
const userContainerEl = createUserItemContainer(socketId); | |
activeUserContainer.appendChild(userContainerEl); | |
} | |
}); | |
} |
I followed this tutorial, and based on the logic, why would you run callUser
after answer-made
? That callback is only called by the original caller to begin with. if you put a log inside callUser()
, it occurs twice.
Also, I had a question as to why no ICE candidate information is required in this tutorial, yet the end result still ends up working?
Thanks for this good tuto !
It works very well with Chrome but not with Safari or Firefox (TypeError: navigator.getUserMedia is not a function).
I tired to replace navigator.getUserMedia by navigator.mediaDevice.getUserMedia but i have an "uncaught exception: Object".
Do you have an idea ?
Hi,
Be careful with "navigator.mediaDevice.getUserMedia" and the syntax to use, i modified it:
navigator.mediaDevices.getUserMedia( { video: true, audio: true }).then( (stream) =>{ const localVideo = document.getElementById("local-video"); ....
If it can help...
Hi,
Could anyone please help me. I'm fairy new to be a developer.
I've got an error after creating index.ts and server.ts thennpm run dev
.
Is there any solution for that? I've googled it, then installed typescript package globally, but not idea what this error is./node_modules/ts-node/src/index.ts:421 return new TSError(diagnosticText, diagnosticCodes) ^ TSError: ⨯ Unable to compile TypeScript:
Did You find a solution to this problem I am facing the same issue, Thanks.
I think on your article you confused the server code with the client (see image).
The code here is not the one should be in index.js right?
I totally missed the part where the client connects to the server. Where is that part?
He made a mistake, this code is in server.ts file, inside of handleSocketConnection function.
Hi,
Could anyone please help me. I'm fairy new to be a developer.
I've got an error after creating index.ts and server.ts thennpm run dev
.
Is there any solution for that? I've googled it, then installed typescript package globally, but not idea what this error is./node_modules/ts-node/src/index.ts:421 return new TSError(diagnosticText, diagnosticCodes) ^ TSError: ⨯ Unable to compile TypeScript:
Did You find a solution to this problem I am facing the same issue, Thanks.
It happened to me and I determined it was just a generic error. The real error was somewhere else. Check the full stack trace that it gives you.
Hi, I was trying to recreate the code and when started with Handle socket connection snippet, author was recommending to look for the socket connected message in console. apparently, I was not able to see "Socket connected" message. I have checked all the git repository files as well. Am I missing something.
Thank you.
V Raj
It is broken it doesn't work mate
…
On Wed 12 Aug, 2020, 10:28 AM VISHNU RAJ C L, @.> wrote: @.* commented on this gist. ------------------------------ Hi, I was trying to recreate the code and when started with Handle socket connection snippet, author was recommending to look for the socket connected message in console. apparently, I was not able to see "Socket connected" message. I have checked all the git repository files as well. Am I missing something. Thank you. V Raj — You are receiving this because you commented. Reply to this email directly, view it on GitHub https://gist.github.com/5d34542fe5274341439ef92de7861cd3#gistcomment-3413866, or unsubscribe https://github.com/notifications/unsubscribe-auth/AH2GJKLJXJ2C3F4BAFTSTTTSAIORDANCNFSM4LQSCDOA .
Thanks Sagarparker ! Is there any other workaround?
in tsconfig.json
{
"compilerOptions": {
"esModuleInterop": true
}
}
to fix import errors
Does anyone know why this code is needed?
on-made-answer.js
if (!isAlreadyCalling) {
callUser(data.socket);
isAlreadyCalling = true;
}
When I place a console.log(socketId); in the callUser function.
I see that the callUser function is called twice with the same socket id as argument.
This code is needed, because without it the application doesn't work.
But can't find a sollution why.
I made an example and fixed all the mistakes of the author.
https://github.com/exzos28/webrtc-echo-server
Hi,
Could anyone please help me. I'm fairy new to be a developer.
I've got an error after creating index.ts and server.ts then
npm run dev
.Is there any solution for that? I've googled it, then installed typescript package globally, but not idea what this error is.