From d446b33695678e441a5761f99e482d139fad3305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5var=20Aamb=C3=B8=20Fosstveit?= Date: Sun, 22 Mar 2020 22:41:48 +0100 Subject: [PATCH 1/7] Room now scales up to total server capacity --- server/lib/Peer.js | 12 +++++++ server/lib/Room.js | 79 +++++++++++++++++++++++++++++++++++++--------- server/server.js | 4 +-- 3 files changed, 78 insertions(+), 17 deletions(-) diff --git a/server/lib/Peer.js b/server/lib/Peer.js index cce62aa..6f886a6 100644 --- a/server/lib/Peer.js +++ b/server/lib/Peer.js @@ -30,6 +30,8 @@ class Peer extends EventEmitter this._email = null; + this._routerId = null; + this._rtpCapabilities = null; this._raisedHand = false; @@ -227,6 +229,16 @@ class Peer extends EventEmitter this._email = email; } + get routerId() + { + return this._routerId; + } + + set routerId(routerId) + { + this._routerId = routerId; + } + get rtpCapabilities() { return this._rtpCapabilities; diff --git a/server/lib/Room.js b/server/lib/Room.js index f25f31d..516af2a 100644 --- a/server/lib/Room.js +++ b/server/lib/Room.js @@ -12,32 +12,38 @@ class Room extends EventEmitter * * @async * - * @param {mediasoup.Worker} mediasoupWorker - The mediasoup Worker in which a new + * @param {mediasoup.Worker} mediasoupWorkers - The mediasoup Worker in which a new * mediasoup Router must be created. * @param {String} roomId - Id of the Room instance. */ - static async create({ mediasoupWorker, roomId }) + static async create({ mediasoupWorkers, roomId }) { logger.info('create() [roomId:"%s"]', roomId); // Router media codecs. const mediaCodecs = config.mediasoup.router.mediaCodecs; - // Create a mediasoup Router. - const mediasoupRouter = await mediasoupWorker.createRouter({ mediaCodecs }); + const mediasoupRouters = []; - // Create a mediasoup AudioLevelObserver. - const audioLevelObserver = await mediasoupRouter.createAudioLevelObserver( + for (const worker of mediasoupWorkers) + { + const router = await worker.createRouter({ mediaCodecs }); + + mediasoupRouters.push(router); + } + + // Create a mediasoup AudioLevelObserver on first router + const audioLevelObserver = await mediasoupRouters[0].createAudioLevelObserver( { maxEntries : 1, threshold : -80, interval : 800 }); - return new Room({ roomId, mediasoupRouter, audioLevelObserver }); + return new Room({ roomId, mediasoupRouters, audioLevelObserver }); } - constructor({ roomId, mediasoupRouter, audioLevelObserver }) + constructor({ roomId, mediasoupRouters, audioLevelObserver }) { logger.info('constructor() [roomId:"%s"]', roomId); @@ -70,8 +76,8 @@ class Room extends EventEmitter this._peers = {}; - // mediasoup Router instance. - this._mediasoupRouter = mediasoupRouter; + // Array of mediasoup Router instances. + this._mediasoupRouters = mediasoupRouters; // mediasoup AudioLevelObserver. this._audioLevelObserver = audioLevelObserver; @@ -108,8 +114,11 @@ class Room extends EventEmitter this._peers = null; - // Close the mediasoup Router. - this._mediasoupRouter.close(); + // Close the mediasoup Routers. + for (const router of this._mediasoupRouters) + { + router.close(); + } // Emit 'close' event. this.emit('close'); @@ -332,6 +341,9 @@ class Room extends EventEmitter this._peers[peer.id] = peer; + // Assign least loaded router + peer.routerId = this._getLeastLoadedRouter(); + this._handlePeer(peer); this._notification(peer.socket, 'roomReady'); } @@ -413,11 +425,14 @@ class Room extends EventEmitter async _handleSocketRequest(peer, request, cb) { + const router = + this._mediasoupRouters.find((peerRouter) => peerRouter.id === peer.routerId); + switch (request.method) { case 'getRouterRtpCapabilities': { - cb(null, this._mediasoupRouter.rtpCapabilities); + cb(null, router.rtpCapabilities); break; } @@ -531,7 +546,7 @@ class Room extends EventEmitter webRtcTransportOptions.enableTcp = true; } - const transport = await this._mediasoupRouter.createWebRtcTransport( + const transport = await router.createWebRtcTransport( webRtcTransportOptions ); @@ -615,6 +630,17 @@ class Room extends EventEmitter const producer = await transport.produce({ kind, rtpParameters, appData }); + for (const destinationRouter of this._mediasoupRouters) + { + if (destinationRouter !== router) + { + await router.pipeToRouter({ + producerId : producer.id, + router : destinationRouter + }); + } + } + // Store the Producer into the Peer data Object. peer.addProducer(producer.id, producer); @@ -1089,6 +1115,9 @@ class Room extends EventEmitter producer.id ); + const router = this._mediasoupRouters.find((producerRouter) => + producerRouter.id === producerPeer.routerId); + // Optimization: // - Create the server-side Consumer. If video, do it paused. // - Tell its Peer about it and wait for its response. @@ -1099,7 +1128,7 @@ class Room extends EventEmitter // NOTE: Don't create the Consumer if the remote Peer cannot consume it. if ( !consumerPeer.rtpCapabilities || - !this._mediasoupRouter.canConsume( + !router.canConsume( { producerId : producer.id, rtpCapabilities : consumerPeer.rtpCapabilities @@ -1292,6 +1321,26 @@ class Room extends EventEmitter socket.emit('notification', { method, data }); } } + + _getLeastLoadedRouter() + { + let load = Infinity; + let id; + + for (const router of this._mediasoupRouters) + { + const routerLoad = + Object.values(this._peers).filter((peer) => peer.routerId === router.id).length; + + if (routerLoad < load) + { + id = router.id; + load = routerLoad; + } + } + + return id; + } } module.exports = Room; diff --git a/server/server.js b/server/server.js index 8faa837..e4f868a 100755 --- a/server/server.js +++ b/server/server.js @@ -570,9 +570,9 @@ async function getOrCreateRoom({ roomId }) { logger.info('creating a new Room [roomId:"%s"]', roomId); - const mediasoupWorker = getMediasoupWorker(); + // const mediasoupWorker = getMediasoupWorker(); - room = await Room.create({ mediasoupWorker, roomId }); + room = await Room.create({ mediasoupWorkers, roomId }); rooms.set(roomId, room); From 698a57cb3eacd2d929a067682fda94c75ef20a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5var=20Aamb=C3=B8=20Fosstveit?= Date: Mon, 23 Mar 2020 14:59:25 +0100 Subject: [PATCH 2/7] Scaling up to new router after this many users connect --- server/lib/Room.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/lib/Room.js b/server/lib/Room.js index 516af2a..23f6d53 100644 --- a/server/lib/Room.js +++ b/server/lib/Room.js @@ -5,6 +5,8 @@ const config = require('../config/config'); const logger = new Logger('Room'); +const ROUTER_SCALE_SIZE = 40; + class Room extends EventEmitter { /** From 207b92cfb23083bec1795c105f85ee640516928f Mon Sep 17 00:00:00 2001 From: Oskars G Date: Mon, 4 May 2020 17:03:00 +0300 Subject: [PATCH 3/7] Add Latvian (LV) localization, by Oskars Galanders Gift to Latvian people on the Day of the Restoration of Latvian Independence /from proprietary software/ :) --- app/src/translations/lv.json | 170 +++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 app/src/translations/lv.json diff --git a/app/src/translations/lv.json b/app/src/translations/lv.json new file mode 100644 index 0000000..dce2204 --- /dev/null +++ b/app/src/translations/lv.json @@ -0,0 +1,170 @@ +{ + "socket.disconnected": "Esat bezsaistē", + "socket.reconnecting": "Esat bezsaistē, tiek mēģināts pievienoties", + "socket.reconnected": "Esat atkārtoti pievienojies", + "socket.requestError": "Kļūme servera pieprasījumā", + + "room.chooseRoom": "Ievadiet sapulces telpas nosaukumu (ID), kurai vēlaties pievienoties", + "room.cookieConsent": "Lai uzlabotu lietotāja pieredzi, šī vietne izmanto sīkfailus", + "room.consentUnderstand": "Es saprotu un piekrītu", + "room.joined": "Jūs esiet pievienojies sapulces telpai", + "room.cantJoin": "Nav iespējams pievienoties sapulces telpai", + "room.youLocked": "Jūs aizslēdzāt sapulces telpu", + "room.cantLock": "Nav iespējams aizslēgt sapulces telpu", + "room.youUnLocked": "Jūs atslēdzāt sapulces telpu", + "room.cantUnLock": "Nav iespējams atslēgt sapulces telpu", + "room.locked": "Sapulces telpa tagad ir AIZSLĒGTA", + "room.unlocked": "Sapulces telpa tagad ir ATSLĒGTA", + "room.newLobbyPeer": "Jauns dalībnieks ienācis uzgaidāmajā telpā", + "room.lobbyPeerLeft": "Dalībnieks uzgaidāmo telpu pameta", + "room.lobbyPeerChangedDisplayName": "Dalībnieks uzgaidāmajā telpā nomainīja vārdu uz {displayName}", + "room.lobbyPeerChangedPicture": "Dalībnieks uzgaidāmajā telpā nomainīja pašattēlu", + "room.setAccessCode": "Pieejas kods sapulces telpai aktualizēts", + "room.accessCodeOn": "Pieejas kods sapulces telpai tagad ir aktivēts", + "room.accessCodeOff": "Pieejas kods sapulces telpai tagad ir deaktivēts (atslēgts)", + "room.peerChangedDisplayName": "{oldDisplayName} pārsaucās par {displayName}", + "room.newPeer": "{displayName} pievienojās sapulces telpai", + "room.newFile": "Pieejams jauns fails", + "room.toggleAdvancedMode": "Pārslēgt uz advancēto režīmu", + "room.setDemocraticView": "Nomainīts izkārtojums uz demokrātisko skatu", + "room.setFilmStripView": "Nomainīts izkārtojums uz diapozitīvu (filmstrip) skatu", + "room.loggedIn": "Jūs esat ierakstījies (sistēmā)", + "room.loggedOut": "Jūs esat izrakstījies (no sistēmas)", + "room.changedDisplayName": "Jūsu vārds mainīts uz {displayName}", + "room.changeDisplayNameError": "Gadījās ķibele ar Jūsu vārda nomaiņu", + "room.chatError": "Nav iespējams nosūtīt tērziņa ziņu", + "room.aboutToJoin": "Jūs grasāties pievienoties sapulcei", + "room.roomId": "Sapulces telpas nosaukums (ID): {roomName}", + "room.setYourName": "Norādiet savu dalības vārdu un izvēlieties kā vēlaties pievienoties sapulcei:", + "room.audioOnly": "Vienīgi audio", + "room.audioVideo": "Audio & video", + "room.youAreReady": "Ok, Jūs esiet gatavi!", + "room.emptyRequireLogin": "Sapulces telpa ir tukša! Jūs varat Ierakstīties sistēmā, lai uzsāktu vadīt sapulci vai pagaidīt kamēr pievienojas sapulces rīkotājs/vadītājs", + "room.locketWait": "Sapulce telpa ir slēgta. Jūs atrodaties tās uzgaidāmajā telpā. Uzkavējieties, kamēr kāds Jūs sapulcē ielaiž ...", + "room.lobbyAdministration": "Uzgaidāmās telpas administrēšana", + "room.peersInLobby": "Dalībnieki uzgaidāmajā telpā", + "room.lobbyEmpty": "Pašreiz uzgaidāmajā telpā neviena nav", + "room.hiddenPeers": "{hiddenPeersCount, plural, one {participant} other {participants}}", + "room.me": "Es", + "room.spotlights": "Aktīvie (referējošie) dalībnieki", + "room.passive": "Pasīvie dalībnieki", + "room.videoPaused": "Šis video ir pauzēts", + "room.muteAll": "Noklusināt visus dalībnieku mikrofonus", + "room.stopAllVideo": "Izslēgt visu dalībnieku kameras", + "room.closeMeeting": "Beigt sapulci", + "room.clearChat": "Nodzēst visus tērziņus", + "room.clearFileSharing": "Notīrīt visus kopīgotos failus", + "room.speechUnsupported": "Jūsu pārlūks neatbalsta balss atpazīšanu", + "room.moderatoractions": "Moderatora rīcība", + "room.raisedHand": "{displayName} pacēla roku", + "room.loweredHand": "{displayName} nolaida roku", + "room.extraVideo": "Papildus video", + + "me.mutedPTT": "Jūs esat noklusināts. Turiet taustiņu SPACE-BAR, lai runātu", + + "roles.gotRole": "Jūs ieguvāt lomu: {role}", + "roles.lostRole": "Jūs zaudējāt lomu: {role}", + + "tooltip.login": "Ierakstīties", + "tooltip.logout": "Izrakstīties", + "tooltip.admitFromLobby": "Ielaist no uzgaidāmās telpas", + "tooltip.lockRoom": "Aizslēgt sapulces telpu", + "tooltip.unLockRoom": "Atlēgt sapulces telpu", + "tooltip.enterFullscreen": "Aktivēt pilnekrāna režīmu", + "tooltip.leaveFullscreen": "Pamest pilnekrānu", + "tooltip.lobby": "Parādīt uzgaidāmo telpu", + "tooltip.settings": "Parādīt iestatījumus", + "tooltip.participants": "Parādīt dalībniekus", + "tooltip.kickParticipant": "Izvadīt (izspert) dalībnieku", + "tooltip.muteParticipant": "Noklusināt dalībnieku", + "tooltip.muteParticipantVideo": "Atslēgt dalībnieka video", + "tooltip.raisedHand": "Pacelt roku", + + "label.roomName": "Sapulces telpas nosaukums (ID)", + "label.chooseRoomButton": "Turpināt", + "label.yourName": "Jūu vārds", + "label.newWindow": "Jauns logs", + "label.fullscreen": "Pilnekrāns", + "label.openDrawer": "Atvērt atvilkni", + "label.leave": "Pamest", + "label.chatInput": "Rakstiet tērziņa ziņu...", + "label.chat": "Tērzētava", + "label.filesharing": "Failu koplietošana", + "label.participants": "Dalībnieki", + "label.shareFile": "Koplietot failu", + "label.fileSharingUnsupported": "Failu koplietošana netiek atbalstīta", + "label.unknown": "Nezināms", + "label.democratic": "Demokrātisks skats", + "label.filmstrip": "Diapozitīvu (filmstrip) skats", + "label.low": "Zema", + "label.medium": "Vidēja", + "label.high": "Augsta (HD)", + "label.veryHigh": "Ļoti augsta (FHD)", + "label.ultra": "Ultra (UHD)", + "label.close": "Aizvērt", + "label.media": "Mediji", + "label.appearence": "Izskats", + "label.advanced": "Advancēts", + "label.addVideo": "Pievienot video", + + "settings.settings": "Iestatījumi", + "settings.camera": "Kamera", + "settings.selectCamera": "Izvēlieties kameru (video ierīci)", + "settings.cantSelectCamera": "Nav iespējams lietot šo kameru (video ierīci)", + "settings.audio": "Skaņas ierīce", + "settings.selectAudio": "Izvēlieties skaņas ierīci", + "settings.cantSelectAudio": "Nav iespējams lietot šo skaņas (audio) ierīci", + "settings.resolution": "Iestatiet jūsu video izšķirtspēju", + "settings.layout": "Sapulces telpas izkārtojums", + "settings.selectRoomLayout": "Iestatiet sapulces telpas izkārtojumu", + "settings.advancedMode": "Advancētais režīms", + "settings.permanentTopBar": "Pastāvīga augšējā (ekrānaugšas) josla", + "settings.lastn": "Jums redzamo video/kameru skaits", + "settings.hiddenControls": "Slēpto mediju vadība", + "settings.notificationSounds": "Paziņojumu skaņas", + + "filesharing.saveFileError": "Nav iespējams saglabāt failu", + "filesharing.startingFileShare": "Tiek mēģināts kopīgot failu", + "filesharing.successfulFileShare": "Fails sekmīgi kopīgots", + "filesharing.unableToShare": "Nav iespējams kopīgot failu", + "filesharing.error": "Atgadījās faila kopīgošanas kļūme", + "filesharing.finished": "Fails ir lejupielādēts", + "filesharing.save": "Saglabāt", + "filesharing.sharedFile": "{displayName} kopīgoja failu", + "filesharing.download": "Lejuplādēt", + "filesharing.missingSeeds": "Ja šis process aizņem ilgu laiku, iespējams nav neviena, kas sēklo (seed) šo torentu. Mēģiniet palūgt kādu atkārtoti augšuplādēt Jūsu gribēto failu.", + + "devices.devicesChanged": "Jūsu ierīces pamainījās. Iestatījumu izvēlnē (dialogā) iestatiet jaunās ierīces.", + + "device.audioUnsupported": "Skaņa (audio) netiek atbalstīta", + "device.activateAudio": "Iespējot/aktivēt mikrofonu (izejošo skaņu)", + "device.muteAudio": "Atslēgt/noklusināt mikrofonu (izejošo skaņu) ", + "device.unMuteAudio": "Ieslēgt mikrofonu (izejošo skaņu)", + + "device.videoUnsupported": "Kamera (izejošais video) netiek atbalstīta", + "device.startVideo": "Ieslēgt kameru (izejošo video)", + "device.stopVideo": "Izslēgt kameru (izejošo video)", + + "device.screenSharingUnsupported": "Ekrāna kopīgošana netiek atbalstīta", + "device.startScreenSharing": "Sākt ekrāna kopīgošanu", + "device.stopScreenSharing": "Beigt ekrāna kopīgošanu", + + "devices.microphoneDisconnected": "Mikrofons atvienots", + "devices.microphoneError": "Atgadījās kļūme, piekļūstot jūsu mikrofonam", + "devices.microPhoneMute": "Mikrofons izslēgts/noklusināts", + "devices.micophoneUnMute": "Mikrofons ieslēgts", + "devices.microphoneEnable": "Mikrofons iespējots", + "devices.microphoneMuteError": "Nav iespējams izslēgt Jūsu mikrofonu", + "devices.microphoneUnMuteError": "Nav iespējams ieslēgt Jūsu mikrofonu", + + "devices.screenSharingDisconnected" : "Ekrāna kopīgošana nenotiek (atvienota)", + "devices.screenSharingError": "Atgadījās kļūme, piekļūstot Jūsu ekrānam", + + "devices.cameraDisconnected": "Kamera atvienota", + "devices.cameraError": "Atgadījās kļūme, piekļūstot Jūsu kamerai", + + "moderator.clearChat": "Moderators nodzēsa tērziņus", + "moderator.clearFiles": "Moderators notīrīja failus", + "moderator.muteAudio": "Moderators noklusināja jūsu mikrofonu", + "moderator.muteVideo": "Moderators atslēdza jūsu kameru" +} From 004fac3d1306e4decfca35b586c9d028b1faf2e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20Mih=C3=A1ly?= Date: Mon, 4 May 2020 21:48:14 +0200 Subject: [PATCH 4/7] Import Latvian translation --- app/src/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/index.js b/app/src/index.js index 90bfa4d..cdefb40 100644 --- a/app/src/index.js +++ b/app/src/index.js @@ -38,6 +38,7 @@ import messagesCzech from './translations/cs'; import messagesItalian from './translations/it'; import messagesUkrainian from './translations/uk'; import messagesTurkish from './translations/tr'; +import messagesLatvian from './translations/lv'; import './index.css'; @@ -63,7 +64,8 @@ const messages = 'cs' : messagesCzech, 'it' : messagesItalian, 'uk' : messagesUkrainian, - 'tr' : messagesTurkish + 'tr' : messagesTurkish, + 'lv' : messagesLatvian }; const locale = navigator.language.split(/[-_]/)[0]; // language without region code From 381f9cd7330f1051c56404ef76387987afc745e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5var=20Aamb=C3=B8=20Fosstveit?= Date: Mon, 4 May 2020 23:33:51 +0200 Subject: [PATCH 5/7] All peers enter the same router up to config.routerScaleSize. Then go to the next one, and keep going until all routers are filled up to config.routerScaleSize. After that simple put peers into routers with least peers. --- server/config/config.example.js | 2 + server/lib/Room.js | 117 +++++++++++++++++++++++++++----- 2 files changed, 103 insertions(+), 16 deletions(-) diff --git a/server/config/config.example.js b/server/config/config.example.js index 740a9ae..3541327 100644 --- a/server/config/config.example.js +++ b/server/config/config.example.js @@ -60,6 +60,8 @@ module.exports = // When truthy, the room will be open to all users when the first // authenticated user has already joined the room. activateOnHostJoin : true, + // Room size before spreading to new router + routerScaleSize : 20, // Mediasoup settings mediasoup : { diff --git a/server/lib/Room.js b/server/lib/Room.js index 23f6d53..2dc2368 100644 --- a/server/lib/Room.js +++ b/server/lib/Room.js @@ -5,7 +5,7 @@ const config = require('../config/config'); const logger = new Logger('Room'); -const ROUTER_SCALE_SIZE = 40; +const ROUTER_SCALE_SIZE = config.routerScaleSize || 20; class Room extends EventEmitter { @@ -25,23 +25,30 @@ class Room extends EventEmitter // Router media codecs. const mediaCodecs = config.mediasoup.router.mediaCodecs; - const mediasoupRouters = []; + const mediasoupRouters = new Map(); + + let firstRouter = null; for (const worker of mediasoupWorkers) { const router = await worker.createRouter({ mediaCodecs }); - mediasoupRouters.push(router); + if (!firstRouter) + firstRouter = router; + + mediasoupRouters.set(router.id, router); } // Create a mediasoup AudioLevelObserver on first router - const audioLevelObserver = await mediasoupRouters[0].createAudioLevelObserver( + const audioLevelObserver = await firstRouter.createAudioLevelObserver( { maxEntries : 1, threshold : -80, interval : 800 }); + firstRouter = null; + return new Room({ roomId, mediasoupRouters, audioLevelObserver }); } @@ -81,6 +88,11 @@ class Room extends EventEmitter // Array of mediasoup Router instances. this._mediasoupRouters = mediasoupRouters; + // The router we are currently putting peers in + this._routerIterator = this._mediasoupRouters.values(); + + this._currentRouter = this._routerIterator.next().value; + // mediasoup AudioLevelObserver. this._audioLevelObserver = audioLevelObserver; @@ -102,8 +114,14 @@ class Room extends EventEmitter this._closed = true; + this._chatHistory = null; + + this._fileHistory = null; + this._lobby.close(); + this._lobby = null; + // Close the peers. for (const peer in this._peers) { @@ -117,11 +135,19 @@ class Room extends EventEmitter this._peers = null; // Close the mediasoup Routers. - for (const router of this._mediasoupRouters) + for (const router of this._mediasoupRouters.values()) { router.close(); } + this._routerIterator = null; + + this._currentRouter = null; + + this._mediasoupRouters.clear(); + + this._audioLevelObserver = null; + // Emit 'close' event. this.emit('close'); } @@ -330,7 +356,7 @@ class Room extends EventEmitter } } - _peerJoining(peer) + async _peerJoining(peer) { peer.socket.join(this._roomId); @@ -343,8 +369,8 @@ class Room extends EventEmitter this._peers[peer.id] = peer; - // Assign least loaded router - peer.routerId = this._getLeastLoadedRouter(); + // Assign routerId + peer.routerId = await this._getRouterId(); this._handlePeer(peer); this._notification(peer.socket, 'roomReady'); @@ -428,7 +454,7 @@ class Room extends EventEmitter async _handleSocketRequest(peer, request, cb) { const router = - this._mediasoupRouters.find((peerRouter) => peerRouter.id === peer.routerId); + this._mediasoupRouters.get(peer.routerId); switch (request.method) { @@ -632,9 +658,11 @@ class Room extends EventEmitter const producer = await transport.produce({ kind, rtpParameters, appData }); - for (const destinationRouter of this._mediasoupRouters) + const pipeRouters = this._getRoutersToPipeTo(peer.routerId); + + for (const [ routerId, destinationRouter ] of this._mediasoupRouters) { - if (destinationRouter !== router) + if (pipeRouters.includes(routerId)) { await router.pipeToRouter({ producerId : producer.id, @@ -1117,8 +1145,7 @@ class Room extends EventEmitter producer.id ); - const router = this._mediasoupRouters.find((producerRouter) => - producerRouter.id === producerPeer.routerId); + const router = this._mediasoupRouters.get(producerPeer.routerId); // Optimization: // - Create the server-side Consumer. If video, do it paused. @@ -1324,19 +1351,77 @@ class Room extends EventEmitter } } + async _pipeProducersToNewRouter() + { + const peersToPipe = + Object.values(this._peers) + .filter((peer) => peer.routerId !== this._currentRouter.id); + + for (const peer of peersToPipe) + { + const srcRouter = this._mediasoupRouters.get(peer.routerId); + + for (const producerId of peer.producers.keys()) + { + await srcRouter.pipeToRouter({ + producerId, + router : this._currentRouter + }); + } + } + } + + async _getRouterId() + { + if (this._currentRouter) + { + const routerLoad = + Object.values(this._peers) + .filter((peer) => peer.routerId === this._currentRouter.id).length; + + if (routerLoad >= ROUTER_SCALE_SIZE) + { + this._currentRouter = this._routerIterator.next().value; + + if (this._currentRouter) + { + await this._pipeProducersToNewRouter(); + + return this._currentRouter.id; + } + } + else + { + return this._currentRouter.id; + } + } + + return this._getLeastLoadedRouter(); + } + + // Returns an array of router ids we need to pipe to + _getRoutersToPipeTo(originRouterId) + { + return Object.values(this._peers) + .map((peer) => peer.routerId) + .filter((routerId, index, self) => + routerId !== originRouterId && self.indexOf(routerId) === index + ); + } + _getLeastLoadedRouter() { let load = Infinity; let id; - for (const router of this._mediasoupRouters) + for (const routerId of this._mediasoupRouters.keys()) { const routerLoad = - Object.values(this._peers).filter((peer) => peer.routerId === router.id).length; + Object.values(this._peers).filter((peer) => peer.routerId === routerId).length; if (routerLoad < load) { - id = router.id; + id = routerId; load = routerLoad; } } From 8c8a00f126cdf062ccb20f0c3cef932c9cce6ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5var=20Aamb=C3=B8=20Fosstveit?= Date: Mon, 4 May 2020 23:53:38 +0200 Subject: [PATCH 6/7] Remove config option that is not used anymore --- server/config/config.example.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/server/config/config.example.js b/server/config/config.example.js index ee41c3d..e8960f7 100644 --- a/server/config/config.example.js +++ b/server/config/config.example.js @@ -246,17 +246,11 @@ module.exports = }, // When truthy, the room will be open to all users when as long as there // are allready users in the room - activateOnHostJoin : true, - // If this is set to true, only signed-in users will be able - // to join a room directly. Non-signed-in users (guests) will - // always be put in the lobby regardless of room lock status. - // If false, there is no difference between guests and signed-in - // users when joining. - requireSignInToAccess : true, + activateOnHostJoin : true, // Room size before spreading to new router - routerScaleSize : 20, + routerScaleSize : 20, // Mediasoup settings - mediasoup : + mediasoup : { numWorkers : Object.keys(os.cpus()).length, // mediasoup Worker settings. From e039423dd5476d605ce7d452a072d71e10039ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9sz=C3=A1ros=20Mih=C3=A1ly?= Date: Tue, 5 May 2020 00:53:31 +0200 Subject: [PATCH 7/7] Fix lint --- app/public/config/config.example.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/public/config/config.example.js b/app/public/config/config.example.js index cf2703d..3f0ce49 100644 --- a/app/public/config/config.example.js +++ b/app/public/config/config.example.js @@ -33,7 +33,7 @@ var config = */ audioOutputSupportedBrowsers : [ - 'chrome', + 'chrome', 'opera' ], // Socket.io request timeout