Created
April 25, 2017 22:37
-
-
Save kwindla/b320ecfbe2b5d0c57e65d271ff9438b2 to your computer and use it in GitHub Desktop.
minimal mediasoup server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
}); | |
} |
How to test it? Should I to test via command line options or via browser with some client side code?
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
What's scenario of this code? For a multiconference room? Or for a ping-pong demo?