Skip to content

Instantly share code, notes, and snippets.

@kwindla
Created April 25, 2017 22:37
Show Gist options
  • Save kwindla/b320ecfbe2b5d0c57e65d271ff9438b2 to your computer and use it in GitHub Desktop.
Save kwindla/b320ecfbe2b5d0c57e65d271ff9438b2 to your computer and use it in GitHub Desktop.
minimal mediasoup server
import cmdLineArgs from 'command-line-args';
import mediasoup from 'mediasoup';
import WebSocket from 'ws';
import {
remove,
find,
sortBy,
reverse,
} from 'lodash';
const cmdLineOpts = cmdLineArgs([
{ name: 'ip', type: String },
{ name: 'most-recent-n', type: Number },
]);
const serverOpts = {
logLevel: 'debug',
numWorkers: 1,
rtcIPv4: true,
rtcIPv6: false,
rtcMinPort: 40000,
rtcMaxPort: 49999,
};
if (cmdLineOpts.ip) {
serverOpts.rtcAnnouncedIPv4 = cmdLineOpts.ip;
}
// ----
const RTCPeerConnection = mediasoup.webrtc.RTCPeerConnection;
const RTCSessionDescription = mediasoup.webrtc.RTCSessionDescription;
let participants = {};
let mtgRoom;
// setup websocket for test signaling
const wss = new WebSocket.Server({ port: 8123 });
wss.on('connection', (webSock) => {
webSock.on('message', handleIncomingWebSocketMessage.bind(null, webSock));
webSock.on('close', () => {
let peerId = find(
Object.keys(participants),
(id) => participants[id].webSock === webSock
);
if (peerId) {
console.log(`${peerId} websocket closed`);
if (participants[peerId].mediaPeer) {
participants[peerId].mediaPeer.close();
}
if (participants[peerId].peerConnection) {
participants[peerId].peerConnection.close();
}
delete participants[peerId];
updateSendersStatus();
} else {
console.log('unknown websocket closed (huh?)');
}
console.log('participant count:', Object.keys(participants).length);
});
});
const sfu = mediasoup.Server(serverOpts);
const roomOptions = {
mediaCodecs : [
{
kind : "audio",
name : "audio/opus",
clockRate : 48000,
payloadType : 100
},
{
kind : "video",
name : "video/vp8",
clockRate : 90000,
payloadType : 123
}
]
};
sfu.createRoom(roomOptions)
.then((soupRoom) => mtgRoom = soupRoom)
.catch((e) => console.error(e));
sfuInternalsDump();
// ----
function handleIncomingWebSocketMessage (webSock, messageText) {
let msg = JSON.parse(messageText);
console.log(`${msg.peerId} incoming ${msg.tag} message`);
switch (msg.tag) {
case 'join':
handleParticipant(webSock, msg)
break;
case 'answer':
handleAnswer(webSock, msg);
break;
}
}
function handleParticipant (webSock, msg) {
webSock.soupClientPeerId = msg.peerId;
let mediaPeer = mtgRoom.Peer(msg.peerId);
let peerConnection = new RTCPeerConnection({
peer: mediaPeer,
usePlanB: true
});
let joinTs = Date.now();
participants[msg.peerId] = { webSock, mediaPeer, peerConnection, joinTs }
updateSendersStatus();
peerConnection.setCapabilities(msg.capabilities)
.then(() => {
sendSdpOffer(msg.peerId);
})
.catch((e) => {
console.error(e);
});
peerConnection.on('negotiationneeded', () => {
console.log('negotiation needed for', msg.peerId);
sendSdpOffer(msg.peerId);
});
console.log('participant count:', Object.keys(participants).length);
}
function handleAnswer (webSock, msg) {
// console.log('ANSWER', msg);
participants[msg.peerId].peerConnection
.setRemoteDescription(new RTCSessionDescription(msg.sdp))
.catch((e) => { console.error(e); });
}
function sendSdpOffer (peerId) {
let pr = participants[peerId];
if (!pr) {
console.error('sendSdpOffer called on unknown peerId', peerId);
}
pr.peerConnection.createOffer({
offerToReceiveAudio: 1,
offerToReceiveVideo: 1
})
.then((desc) => {
return pr.peerConnection.setLocalDescription(desc);
})
.then(() => {
pr.webSock.send(JSON.stringify(
{ tag: 'offer',
sendVideo: pr.sendVideo,
sdp: pr.peerConnection.localDescription.serialize()
}));
})
.catch((e) => {
console.error(e);
pr.peerConnection.reset();
});
}
function updateSendersStatus () {
let sortedIds = reverse(sortBy(Object.keys(participants),
(id) => participants[id].joinTs));
let numSenders = cmdLineOpts['most-recent-n'] || 9999;
let cnt = 0;
sortedIds.forEach((id) => {
if (cnt < numSenders) {
participants[id].sendVideo = true;
} else {
participants[id].sendVideo = false;
}
console.log('p', id, participants[id].joinTs, participants[id].sendVideo);
cnt = cnt + 1;
});
}
function sfuInternalsDump() {
sfu.dump()
.then((internals) => {
console.log('--- sfu internals ---\n', JSON.stringify(internals),
'\n---------------------');
})
.catch((e) => {
console.error(e);
});
}
@Globik
Copy link

Globik commented Apr 29, 2017

What's scenario of this code? For a multiconference room? Or for a ping-pong demo?

@Globik
Copy link

Globik commented Apr 29, 2017

How to test it? Should I to test via command line options or via browser with some client side code?

@Globik
Copy link

Globik commented Apr 29, 2017

What cmdLineOpts.ip should to show me: a private ip or public?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment